Compare commits

..
Author SHA1 Message Date
bridgewaterrobbie 815629f14e Quick fix for descriptor set types. 2025-05-15 15:33:47 -04:00
bridgewaterrobbie c05a446e10 Minor fixes to branch hacks. Use unfilterable float instead of float (Might need to vary this depending on eventual filtering bit) 2025-05-15 15:33:36 -04:00
bridgewaterrobbie 9d49205844 Filament's compareMode function should be checked before using any of the comparison related enums it provides. This also lets us use the descriptor now. 2025-05-15 15:32:19 -04:00
bridgewaterrobbie 7099b6dd6f Quick and dirty hack to log where dummies are needed to work still 2025-05-14 20:13:42 -04:00
Mathias Agopian 18becfc656 Make sure that all descriptors are always initialized 2025-05-14 20:13:42 -04:00
bridgewaterrobbie cd2d499e25 Tinkering with new descriptortype info 2025-05-14 15:39:16 -04:00
Mathias Agopian 3bb72cefe9 fix fog sampler descriptor type 2025-05-14 15:39:16 -04:00
Mathias Agopian 1a67f9233b DescriptorType now includes the "dimension" of the texture
DescriptorType now also encodes wether the descriptor expects a 2D, 3D,
Cubemap and/or Array.

This is needed by both Metal and WebGPU.

[**New Material Version**]
2025-05-12 14:10:20 -04:00
Mathias Agopian f7e20562a8 select the proper descriptor set layout in the rendering loop
Now that the per-view layout can be different based on the type of
shadow, we need to make sure we set the proper layout in the pipeline
and use the corresponding descriptor set.

There are now 16 "per-view" layouts and their corresponding descriptor
set. There are two sets of 8, the current set is determined by the
shadow type on the view.

Then during rendering, when we set the pipeline we need to select the
corresponding layout; each material now offers both versions of the
layout and we just pick the right one.

DescriptorSet::setBuffer and setSampler now need the layout in order
to do some validation that the correct type of descriptor is used.
This will help catch problems earlier.
2025-05-12 14:10:19 -04:00
Mathias Agopian 08af16239c add sampler type in DescriptorSetLayout
[**New Material Version**]
2025-05-12 14:10:19 -04:00
Sungun Park 52eb682498 Update MATERIAL_VERSION to 60 2025-05-12 16:45:36 +00:00
Mathias Agopian 5a5168a191 CString tidy cleanup and rvalue methods
We add rvalue version of append/insert/replace so that calling
those on a temporary yields to a temporary.

Also add string literal versions of those so that we can 
append/insert/replace a literal without allocation, e.g.:

`CString foo = CString{ bar }.append("baz");`

This will not end-up creating a temporary CString for "baz".
2025-05-09 16:14:01 -07:00
Powei Feng e85dfe75c8 github: move test script to /test and same for /build (#8714)
- Moved get_mesa.sh to build/common/get-mesa.sh
- Moved check-headers.sh to test/check-headers/test.sh
- Moved check-metal-shaders.sh to test/check-metal-shaders/test.sh
2025-05-09 22:35:18 +00:00
Logan Lawrence 6beb40b0a1 Update release.yml to include native android build files (#8694) 2025-05-09 17:25:00 +00:00
Powei Feng 5cb96e5732 Clean up ndk version in build.sh (#8717)
Follow up to #8663
2025-05-09 15:51:30 +00:00
Matthew Hoffman 927aa57a4e Document ASAN (with leak detection) on MacOS (#8716)
* Revert "Optional CMake flag for enabling ASAN for backend and its tests. (#8696)"

This reverts commit 543b93939a.
There were other already existing ways to achieve this without the need for new flags.

* Add documentation on running with ASAN and leak detection on mac.

BUGS=[398198310]
2025-05-09 10:22:29 -05:00
Powei Feng 36e775902d renderdiff: script for updating golden images (#8709)
Adding a python script to enable updating new goldens into
a staging branch in the golden repo (filament-assets).

The same script can be used in github workflow to automatically
create a golden staging branch. This will be useful for users
without access to a mac (the only platform for generating
goldens as of now).
2025-05-08 22:07:17 +00:00
Powei Feng 53e28f3b33 github: fix release mac build (#8713) 2025-05-08 11:44:08 -07:00
86 changed files with 2371 additions and 814 deletions
+1 -1
View File
@@ -26,4 +26,4 @@ jobs:
path: out/filament-release-darwin.tgz
- name: Check public headers
run: |
build/common/check-headers.sh out/release/filament/include
test/check-headers/test.sh out/release/filament/include
+3 -3
View File
@@ -131,7 +131,7 @@ jobs:
- name: Prerequisites
id: prereqs
run: |
bash test/utils/get_mesa.sh
bash build/common/get-mesa.sh
pip install tifffile numpy
- name: Run Test
run: bash test/renderdiff/test.sh
@@ -153,8 +153,8 @@ jobs:
- name: Run test
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
code-correctness:
name: code-correctness
test-code-correctness:
name: test-code-correctness
runs-on: 'macos-14-xlarge'
steps:
- uses: actions/checkout@v4.1.6
+5 -6
View File
@@ -65,13 +65,9 @@ jobs:
build-mac:
name: build-mac
runs-on: ${{ matrix.os }}
runs-on: macos-14-xlarge
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
strategy:
matrix:
os: [macos-14-xlarge, ubuntu-22.04-32core]
steps:
- name: Decide Git ref
id: git_ref
@@ -167,6 +163,9 @@ jobs:
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
cd out/android-release/filament
tar -czf ../../filament-${TAG}-android-native.tgz .
cd ../../..
- name: Sign sample-gltf-viewer
run: |
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
@@ -188,7 +187,7 @@ jobs:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
const globber = await glob.create(['out/*.aar', 'out/*.apk', 'out/*.tgz'].join('\n'));
await upload({ github, context }, await globber.glob(), TAG);
build-ios:
+1
View File
@@ -8,3 +8,4 @@ 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.60.0'
implementation 'com.google.android.filament:filament-android:1.59.5'
}
```
@@ -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.60.0'
pod 'Filament', '~> 1.59.5'
```
## Documentation
+1 -3
View File
@@ -10,9 +10,7 @@ Instead, if you are authoring a PR for the main branch, add your release note to
## v1.60.0
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
- matc non-functional change: Update GLSL postprocessor to
isolate calls to SPVRemap from calls to SPIRV-Cross.
- `ColorGrading::Builder::toneMapper` now takes a `shared_ptr<ToneMapper>`
## v1.59.5
@@ -18,6 +18,7 @@
#include <filament/ColorGrading.h>
#include <filament/ToneMapper.h>
#include <memory>
#include <math/vec3.h>
#include <math/vec4.h>
@@ -67,8 +68,9 @@ extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_ColorGrading_nBuilderToneMapper(JNIEnv*, jclass,
jlong nativeBuilder, jlong toneMapper_) {
ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder;
const ToneMapper* toneMapper = (const ToneMapper*) toneMapper_;
builder->toneMapper(toneMapper);
ToneMapper* toneMapper = reinterpret_cast<ToneMapper*>(toneMapper_);
std::shared_ptr<ToneMapper> toneMapperCopy(toneMapper->clone());
builder->toneMapper(toneMapperCopy);
}
#pragma clang diagnostic push
@@ -214,9 +214,9 @@ public class ColorGrading {
*
* The default tone mapping operator is {@link ToneMapper.ACESLegacy}.
*
* The specified tone mapper must have a lifecycle that exceeds the lifetime of
* this builder. Since the build(Engine&) method is synchronous, it is safe to
* delete the tone mapper object after that finishes executing.
* The copy of the specified tone mapper is set to this builder. It is safe to delete
* the original tone mapper object while the copied one is held by the built ColorGrading
* object.
*
* @param toneMapper The tone mapping operator to apply to the HDR color buffer
*
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.60.0
VERSION_NAME=1.59.5
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -1
View File
@@ -151,7 +151,7 @@ function print_fgviewer_help {
}
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")}
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | cut -f 1 -d ".")}
# Requirements
CMAKE_MAJOR=3
@@ -14,9 +14,9 @@
#!/usr/bin/bash
set -x
set -e
if [[ "$GITHUB_WORKFLOW" ]]; then
set -e
set -x
fi
OS_NAME=$(uname -s)
@@ -35,7 +35,7 @@ source ${ORIG_DIR}/venv/bin/activate
NEEDED_PYTHON_DEPS=("mako" "setuptools" "pyyaml")
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
if ! python3 -m pip show "${cmd}" >/dev/null 2>&1; then
if ! python3 -m pip show -q "${cmd}" >/dev/null 2>&1; then
python3 -m pip install ${cmd}
fi
done
@@ -145,6 +145,6 @@ deactivate
popd
if [[ "$GITHUB_WORKFLOW" ]]; then
set +e
set +x
fi
set +x
set +e
+1
View File
@@ -18,6 +18,7 @@
- [Metal](./notes/metal_debugging.md)
- [Vulkan](./notes/vulkan_debugging.md)
- [SPIR-V](./notes/spirv_debugging.md)
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
- [bluevk](./dup/bluevk.md)
+41
View File
@@ -0,0 +1,41 @@
# Running with ASAN/UBSAN
## Enabling
When building though build.sh, pass the `-b` flag. This sets the cmake variable
`FILAMENT_ENABLE_ASAN_UBSAN=ON` which eventually passes `"-fsanitize=address -fsanitize=undefined"`
to all compile and link operations.
If building through CMake directly, or an IDE like CLion that doesn't use build.sh, instead pass
`-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to cmake in order to get the same result.
## Getting memory leak detection on Mac
Memory leak detection isn't enabled by default on MacOS. There are two issues to address, first is
using a version of clang that supports memory leak detection and second is enabling it at runtime.
The version of clang distributed by Apple (with a version like "Apple clang version 16.0.0") doesn't
currently support leak detection at all. Instead you will need to get or build a different LLVM,
such as the one distributed through homebrew and get CMake to use that instead.
Then during runtime you'll need to have the environment variable `ASAN_OPTIONS` include the option
`detect_leaks=1`. Multiple `ASAN_OPTIONS` values are concatenated with `:`.
## Getting memory leak output in CLion
### Setting variables
Under `Settings | Build, Execution, Deployment | Dynamic Analysis Tools | Sanitizers` there is an
ASAN Settings field that overrides whatever other `ASAN_OPTIONS` you might set elsewhere, so you
must use that instead of setting it through your Run/Debug Configuration.
To pass `-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to CMake you'll want to create a new CMake Profile and
pass it as a CMake argument.
### Avoiding losing output
CMake will consume ASAN output and display it through a separate "Sanitizers" tab. Unfortunately
certain leak detection errors that interrupt the executable seem to not show up in this tab, but are
still removed from the user-visible console output. If this is happening and you need to see the
unfiltered console output you'll need to go to `Settings | Build, Execution, Deployment | Dynamic
Analysis Tools | Sanitizers` and uncheck "Use visual representation for Sanitizer's output".
-20
View File
@@ -5,18 +5,6 @@ set(TARGET backend)
set(PUBLIC_HDR_DIR include)
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
# ==================================================================================================
# Compilation options
# ==================================================================================================
#
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
set(BACKEND_SANITIZERS)
if (BACKEND_SANITIZATION STREQUAL "ASAN")
set(BACKEND_SANITIZERS -fsanitize=address)
endif()
# ==================================================================================================
# Sources and headers
# ==================================================================================================
@@ -484,7 +472,6 @@ target_compile_options(${TARGET} PRIVATE
${OSMESA_COMPILE_FLAGS}
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
${BACKEND_SANITIZERS}
)
if (FILAMENT_SUPPORTS_METAL)
@@ -495,8 +482,6 @@ if (FILAMENT_SUPPORTS_WEBGPU)
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
endif()
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(${TARGET} PRIVATE
${OSMESA_LINKER_FLAGS}
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
@@ -566,8 +551,6 @@ if (APPLE AND NOT IOS)
test/test_RenderExternalImage.cpp)
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
set(BACKEND_TEST_DEPS
OSDependent
@@ -606,7 +589,6 @@ if (APPLE AND NOT IOS)
# linker from removing "unused" symbols.
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
# This is needed after XCode 15.3
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
@@ -616,8 +598,6 @@ endif()
if (LINUX)
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
endif()
+183 -34
View File
@@ -37,6 +37,7 @@
#include <array>
#include <type_traits>
#include <variant>
#include <string_view>
#include <stddef.h>
#include <stdint.h>
@@ -159,7 +160,7 @@ enum class TimerQueryResult : int8_t {
AVAILABLE = 1, // result is available
};
static constexpr const char* backendToString(Backend backend) {
constexpr std::string_view to_string(Backend const backend) noexcept {
switch (backend) {
case Backend::NOOP:
return "Noop";
@@ -171,9 +172,11 @@ static constexpr const char* backendToString(Backend backend) {
return "Metal";
case Backend::WEBGPU:
return "WebGPU";
default:
return "Unknown";
case Backend::DEFAULT:
return "Default";
break;
}
return "Unknown";
}
/**
@@ -190,7 +193,7 @@ enum class ShaderLanguage {
WGSL = 5,
};
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) noexcept {
switch (shaderLanguage) {
case ShaderLanguage::ESSL1:
return "ESSL 1.0";
@@ -205,6 +208,7 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
case ShaderLanguage::WGSL:
return "WGSL";
}
return "UNKNOWN";
}
enum class ShaderStage : uint8_t {
@@ -222,7 +226,7 @@ enum class ShaderStageFlags : uint8_t {
ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE
};
static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
switch (type) {
case ShaderStage::VERTEX:
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX));
@@ -233,14 +237,114 @@ static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage t
}
}
enum class DescriptorType : uint8_t {
UNIFORM_BUFFER,
SHADER_STORAGE_BUFFER,
SAMPLER,
INPUT_ATTACHMENT,
SAMPLER_EXTERNAL
enum class TextureType : uint8_t {
FLOAT,
INT,
UINT,
DEPTH,
STENCIL,
DEPTH_STENCIL
};
constexpr std::string_view to_string(TextureType type) noexcept {
switch (type) {
case TextureType::FLOAT: return "FLOAT";
case TextureType::INT: return "INT";
case TextureType::UINT: return "UINT";
case TextureType::DEPTH: return "DEPTH";
case TextureType::STENCIL: return "STENCIL";
case TextureType::DEPTH_STENCIL: return "DEPTH_STENCIL";
}
return "UNKNOWN";
}
enum class DescriptorType : uint8_t {
SAMPLER_2D_FLOAT,
SAMPLER_2D_INT,
SAMPLER_2D_UINT,
SAMPLER_2D_DEPTH,
SAMPLER_2D_ARRAY_FLOAT,
SAMPLER_2D_ARRAY_INT,
SAMPLER_2D_ARRAY_UINT,
SAMPLER_2D_ARRAY_DEPTH,
SAMPLER_CUBE_FLOAT,
SAMPLER_CUBE_INT,
SAMPLER_CUBE_UINT,
SAMPLER_CUBE_DEPTH,
SAMPLER_CUBE_ARRAY_FLOAT,
SAMPLER_CUBE_ARRAY_INT,
SAMPLER_CUBE_ARRAY_UINT,
SAMPLER_CUBE_ARRAY_DEPTH,
SAMPLER_3D_FLOAT,
SAMPLER_3D_INT,
SAMPLER_3D_UINT,
SAMPLER_EXTERNAL,
UNIFORM_BUFFER,
SHADER_STORAGE_BUFFER,
INPUT_ATTACHMENT,
};
constexpr bool isDepthDescriptor(DescriptorType const type) noexcept {
switch (type) {
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
return true;
default: ;
}
return false;
}
constexpr bool isFloatDescriptor(DescriptorType const type) noexcept {
switch (type) {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_3D_FLOAT:
return true;
default: ;
}
return false;
}
constexpr std::string_view to_string(DescriptorType type) noexcept {
#define DESCRIPTOR_TYPE_CASE(TYPE) case DescriptorType::TYPE: return #TYPE;
switch (type) {
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_FLOAT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_INT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_UINT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_DEPTH)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_FLOAT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_INT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_UINT)
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_DEPTH)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_FLOAT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_INT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_UINT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_DEPTH)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_FLOAT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_INT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_UINT)
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_DEPTH)
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_FLOAT)
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_INT)
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_UINT)
DESCRIPTOR_TYPE_CASE(SAMPLER_EXTERNAL)
DESCRIPTOR_TYPE_CASE(UNIFORM_BUFFER)
DESCRIPTOR_TYPE_CASE(SHADER_STORAGE_BUFFER)
DESCRIPTOR_TYPE_CASE(INPUT_ATTACHMENT)
}
return "UNKNOWN";
#undef DESCRIPTOR_TYPE_CASE
}
enum class DescriptorFlags : uint8_t {
NONE = 0x00,
DYNAMIC_OFFSET = 0x01
@@ -251,6 +355,13 @@ using descriptor_set_t = uint8_t;
using descriptor_binding_t = uint8_t;
struct DescriptorSetLayoutBinding {
static bool isSampler(DescriptorType type) noexcept {
return int(type) <= int(DescriptorType::SAMPLER_EXTERNAL);
}
static bool isBuffer(DescriptorType type) noexcept {
return type == DescriptorType::UNIFORM_BUFFER ||
type == DescriptorType::SHADER_STORAGE_BUFFER;
}
DescriptorType type;
ShaderStageFlags stageFlags;
descriptor_binding_t binding;
@@ -261,7 +372,7 @@ struct DescriptorSetLayoutBinding {
// no uninitialized padding bytes.
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
friend inline bool operator==(DescriptorSetLayoutBinding const& lhs,
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
DescriptorSetLayoutBinding const& rhs) noexcept {
return lhs.type == rhs.type &&
lhs.flags == rhs.flags &&
@@ -294,7 +405,7 @@ enum class TargetBufferFlags : uint32_t {
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
};
inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
if (index == 0u) return TargetBufferFlags::COLOR0;
if (index == 1u) return TargetBufferFlags::COLOR1;
if (index == 2u) return TargetBufferFlags::COLOR2;
@@ -451,6 +562,24 @@ enum class SamplerType : uint8_t {
SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2)
};
constexpr std::string_view to_string(SamplerType const type) noexcept {
switch (type) {
case SamplerType::SAMPLER_2D:
return "SAMPLER_2D";
case SamplerType::SAMPLER_2D_ARRAY:
return "SAMPLER_2D_ARRAY";
case SamplerType::SAMPLER_CUBEMAP:
return "SAMPLER_CUBEMAP";
case SamplerType::SAMPLER_EXTERNAL:
return "SAMPLER_EXTERNAL";
case SamplerType::SAMPLER_3D:
return "SAMPLER_3D";
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
return "SAMPLER_CUBEMAP_ARRAY";
}
return "Unknown";
}
//! Subpass type
enum class SubpassType : uint8_t {
SUBPASS_INPUT
@@ -464,6 +593,20 @@ enum class SamplerFormat : uint8_t {
SHADOW = 3 //!< shadow sampler (PCF)
};
constexpr std::string_view to_string(SamplerFormat const format) noexcept {
switch (format) {
case SamplerFormat::INT:
return "INT";
case SamplerFormat::UINT:
return "UINT";
case SamplerFormat::FLOAT:
return "FLOAT";
case SamplerFormat::SHADOW:
return "SHADOW";
}
return "Unknown";
}
/**
* Supported element types
*/
@@ -764,6 +907,8 @@ enum class TextureFormat : uint16_t {
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
};
TextureType getTextureType(TextureFormat format) noexcept;
//! Bitmask describing the intended Texture Usage
enum class TextureUsage : uint16_t {
NONE = 0x0000,
@@ -791,7 +936,7 @@ enum class TextureSwizzle : uint8_t {
};
//! returns whether this format a depth format
static constexpr bool isDepthFormat(TextureFormat format) noexcept {
constexpr bool isDepthFormat(TextureFormat format) noexcept {
switch (format) {
case TextureFormat::DEPTH32F:
case TextureFormat::DEPTH24:
@@ -804,7 +949,7 @@ static constexpr bool isDepthFormat(TextureFormat format) noexcept {
}
}
static constexpr bool isStencilFormat(TextureFormat format) noexcept {
constexpr bool isStencilFormat(TextureFormat format) noexcept {
switch (format) {
case TextureFormat::STENCIL8:
case TextureFormat::DEPTH24_STENCIL8:
@@ -815,7 +960,7 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept {
}
}
inline constexpr bool isColorFormat(TextureFormat format) noexcept {
constexpr bool isColorFormat(TextureFormat format) noexcept {
switch (format) {
// Standard color formats
case TextureFormat::R8:
@@ -842,7 +987,7 @@ inline constexpr bool isColorFormat(TextureFormat format) noexcept {
return false;
}
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
constexpr bool isUnsignedIntFormat(TextureFormat format) {
switch (format) {
case TextureFormat::R8UI:
case TextureFormat::R16UI:
@@ -863,7 +1008,7 @@ static constexpr bool isUnsignedIntFormat(TextureFormat format) {
}
}
static constexpr bool isSignedIntFormat(TextureFormat format) {
constexpr bool isSignedIntFormat(TextureFormat format) {
switch (format) {
case TextureFormat::R8I:
case TextureFormat::R16I:
@@ -885,35 +1030,35 @@ static constexpr bool isSignedIntFormat(TextureFormat format) {
}
//! returns whether this format is a compressed format
static constexpr bool isCompressedFormat(TextureFormat format) noexcept {
constexpr bool isCompressedFormat(TextureFormat format) noexcept {
return format >= TextureFormat::EAC_R11;
}
//! returns whether this format is an ETC2 compressed format
static constexpr bool isETC2Compression(TextureFormat format) noexcept {
constexpr bool isETC2Compression(TextureFormat format) noexcept {
return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8;
}
//! returns whether this format is an S3TC compressed format
static constexpr bool isS3TCCompression(TextureFormat format) noexcept {
constexpr bool isS3TCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA;
}
static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
}
//! returns whether this format is an RGTC compressed format
static constexpr bool isRGTCCompression(TextureFormat format) noexcept {
constexpr bool isRGTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2;
}
//! returns whether this format is an BPTC compressed format
static constexpr bool isBPTCCompression(TextureFormat format) noexcept {
constexpr bool isBPTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM;
}
static constexpr bool isASTCCompression(TextureFormat format) noexcept {
constexpr bool isASTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
}
@@ -1038,15 +1183,19 @@ struct SamplerParams { // NOLINT
}
};
bool isFiltered() const noexcept {
return filterMag != SamplerMagFilter::NEAREST || filterMin != SamplerMinFilter::NEAREST;
}
private:
friend inline bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
return SamplerParams::EqualTo{}(lhs, rhs);
friend bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
return EqualTo{}(lhs, rhs);
}
friend inline bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
return !SamplerParams::EqualTo{}(lhs, rhs);
friend bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
return !EqualTo{}(lhs, rhs);
}
friend inline bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
return SamplerParams::LessThan{}(lhs, rhs);
friend bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
return LessThan{}(lhs, rhs);
}
};
@@ -1096,15 +1245,15 @@ struct SamplerYcbcrConversion {// NOLINT
};
private:
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
friend bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
}
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
friend bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
}
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
friend bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
noexcept {
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
}
@@ -149,13 +149,6 @@ public:
* - PlatformEGLAndroid
*/
bool assertNativeWindowIsValid = false;
/**
* The action to take if a Drawable cannot be acquired. If true, the
* frame is aborted instead of panic. This is only supported for:
* - PlatformMetal
*/
bool metalDisablePanicOnDrawableFailure = false;
};
Platform() noexcept;
+139
View File
@@ -18,6 +18,8 @@
#include "DataReshaper.h"
#include <backend/DriverEnums.h>
#include <utils/CString.h>
#include <string_view>
@@ -223,6 +225,143 @@ size_t getFormatSize(TextureFormat format) noexcept {
}
}
TextureType getTextureType(TextureFormat const format) noexcept {
switch (format) {
case TextureFormat::UNUSED:
// should not happen
return TextureType::FLOAT;
case TextureFormat::R8:
case TextureFormat::R16F:
case TextureFormat::RG8:
case TextureFormat::RGB565:
case TextureFormat::RGB5_A1:
case TextureFormat::RGBA4:
case TextureFormat::R32F:
case TextureFormat::RGB8:
case TextureFormat::SRGB8:
case TextureFormat::RG16F:
case TextureFormat::R11F_G11F_B10F:
case TextureFormat::RGB9_E5:
case TextureFormat::RGBA8:
case TextureFormat::SRGB8_A8:
case TextureFormat::RGB10_A2:
case TextureFormat::RGB16F:
case TextureFormat::RG32F:
case TextureFormat::RGBA16F:
case TextureFormat::RGB32F:
case TextureFormat::RGBA32F:
return TextureType::FLOAT;
case TextureFormat::R8_SNORM:
case TextureFormat::RG8_SNORM:
case TextureFormat::RGB8_SNORM:
case TextureFormat::RGBA8_SNORM:
// SNORM are treated as float
return TextureType::FLOAT;
case TextureFormat::R8UI:
case TextureFormat::R16UI:
case TextureFormat::RG8UI:
case TextureFormat::RGB8UI:
case TextureFormat::R32UI:
case TextureFormat::RG16UI:
case TextureFormat::RGBA8UI:
case TextureFormat::RGB16UI:
case TextureFormat::RG32UI:
case TextureFormat::RGBA16UI:
case TextureFormat::RGB32UI:
case TextureFormat::RGBA32UI:
return TextureType::UINT;
case TextureFormat::R8I:
case TextureFormat::R16I:
case TextureFormat::RG8I:
case TextureFormat::RGB8I:
case TextureFormat::R32I:
case TextureFormat::RG16I:
case TextureFormat::RGBA8I:
case TextureFormat::RGB16I:
case TextureFormat::RG32I:
case TextureFormat::RGBA16I:
case TextureFormat::RGB32I:
case TextureFormat::RGBA32I:
return TextureType::INT;
case TextureFormat::DEPTH16:
case TextureFormat::DEPTH24:
case TextureFormat::DEPTH32F:
return TextureType::DEPTH;
case TextureFormat::STENCIL8:
return TextureType::STENCIL;
case TextureFormat::DEPTH24_STENCIL8:
case TextureFormat::DEPTH32F_STENCIL8:
return TextureType::DEPTH_STENCIL;
// Compressed formats ---------------------------------------------------------------------
case TextureFormat::EAC_RG11:
case TextureFormat::EAC_RG11_SIGNED:
case TextureFormat::ETC2_EAC_RGBA8:
case TextureFormat::ETC2_EAC_SRGBA8:
case TextureFormat::EAC_R11:
case TextureFormat::EAC_R11_SIGNED:
case TextureFormat::ETC2_RGB8:
case TextureFormat::ETC2_SRGB8:
case TextureFormat::ETC2_RGB8_A1:
case TextureFormat::ETC2_SRGB8_A1:
case TextureFormat::DXT1_RGB:
case TextureFormat::DXT1_RGBA:
case TextureFormat::DXT1_SRGB:
case TextureFormat::DXT1_SRGBA:
case TextureFormat::DXT3_RGBA:
case TextureFormat::DXT3_SRGBA:
case TextureFormat::DXT5_RGBA:
case TextureFormat::DXT5_SRGBA:
case TextureFormat::RED_RGTC1:
case TextureFormat::SIGNED_RED_RGTC1:
case TextureFormat::RED_GREEN_RGTC2:
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
case TextureFormat::RGBA_BPTC_UNORM:
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
case TextureFormat::RGBA_ASTC_4x4:
case TextureFormat::RGBA_ASTC_5x4:
case TextureFormat::RGBA_ASTC_5x5:
case TextureFormat::RGBA_ASTC_6x5:
case TextureFormat::RGBA_ASTC_6x6:
case TextureFormat::RGBA_ASTC_8x5:
case TextureFormat::RGBA_ASTC_8x6:
case TextureFormat::RGBA_ASTC_8x8:
case TextureFormat::RGBA_ASTC_10x5:
case TextureFormat::RGBA_ASTC_10x6:
case TextureFormat::RGBA_ASTC_10x8:
case TextureFormat::RGBA_ASTC_10x10:
case TextureFormat::RGBA_ASTC_12x10:
case TextureFormat::RGBA_ASTC_12x12:
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
return TextureType::FLOAT;
}
return TextureType::FLOAT;
}
size_t getFormatComponentCount(TextureFormat format) noexcept {
switch (format) {
case TextureFormat::R8:
+2 -16
View File
@@ -672,22 +672,8 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
// nothing to do, timer query was constructed in createTimerQueryS
}
const char* toString(DescriptorType type) {
switch (type) {
case DescriptorType::UNIFORM_BUFFER:
return "UNIFORM_BUFFER";
case DescriptorType::SHADER_STORAGE_BUFFER:
return "SHADER_STORAGE_BUFFER";
case DescriptorType::SAMPLER:
return "SAMPLER";
case DescriptorType::INPUT_ATTACHMENT:
return "INPUT_ATTACHMENT";
case DescriptorType::SAMPLER_EXTERNAL:
return "SAMPLER_EXTERNAL";
}
}
const char* toString(ShaderStageFlags flags) {
UTILS_UNUSED
static const char* toString(ShaderStageFlags flags) {
std::vector<const char*> stages;
if (any(flags & ShaderStageFlags::VERTEX)) {
stages.push_back("VERTEX");
+38 -2
View File
@@ -1356,7 +1356,25 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
[arguments addObject:bufferArgument];
break;
}
case DescriptorType::SAMPLER:
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
case DescriptorType::SAMPLER_EXTERNAL: {
MTLArgumentDescriptor* textureArgument = [MTLArgumentDescriptor argumentDescriptor];
textureArgument.index = binding.binding * 2;
@@ -1472,7 +1490,25 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
atIndex:binding.binding * 2];
break;
}
case DescriptorType::SAMPLER:
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
case DescriptorType::SAMPLER_EXTERNAL: {
auto found = textures.find(binding.binding);
if (found == textures.end()) {
@@ -45,9 +45,6 @@ PlatformMetal::~PlatformMetal() noexcept {
}
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure
? DrawableFailureBehavior::ABORT_FRAME
: DrawableFailureBehavior::PANIC;
return MetalDriverFactory::create(this, driverConfig);
}
+2 -3
View File
@@ -69,9 +69,8 @@ public:
assert_invariant(set < MAX_DESCRIPTOR_SET_COUNT);
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
mStorage[set][binding] = { (uint8_t)entry.binding,
entry.type == DescriptorType::SAMPLER ||
entry.type == DescriptorType::SAMPLER_EXTERNAL };
mStorage[set][binding] = { uint8_t(entry.binding),
DescriptorSetLayoutBinding::isSampler(entry.type) };
mActiveDescriptors[set].set(binding);
}
@@ -95,7 +95,26 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
}
break;
}
case DescriptorType::SAMPLER:
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
case DescriptorType::SAMPLER_EXTERNAL:
if (UTILS_UNLIKELY(gl.isES2())) {
desc.emplace<SamplerGLES2>();
+19 -1
View File
@@ -175,7 +175,25 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
}
break;
}
case DescriptorType::SAMPLER:
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
case DescriptorType::SAMPLER_EXTERNAL: {
if (!entry.name.empty()) {
GLint const loc = glGetUniformLocation(program, entry.name.c_str());
+20 -1
View File
@@ -93,7 +93,26 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
case DescriptorType::SAMPLER_EXTERNAL:
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
UTILS_FALLTHROUGH;
case DescriptorType::SAMPLER: {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT: {
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
break;
}
+82 -81
View File
@@ -469,7 +469,7 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
mDevice, flags);
assert_invariant(mSwapChain);
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
mSwapChain->getColorFormat());
mSwapChain->getColorFormat(), mSwapChain->getDepthFormat());
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
"background components have been instantiated/selected, such as surface/screen, "
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
@@ -591,7 +591,7 @@ void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh) {
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getBindGroupEntries());
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getBindGroupEntries(), layout->label);
}
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
@@ -1069,97 +1069,98 @@ wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
switch (params.filterMag) {
case SamplerMagFilter::NEAREST: {
desc.magFilter = wgpu::FilterMode::Nearest;
break;
if (params.compareMode == SamplerCompareMode::COMPARE_TO_TEXTURE) {
switch (params.filterMag) {
case SamplerMagFilter::NEAREST: {
desc.magFilter = wgpu::FilterMode::Nearest;
break;
}
case SamplerMagFilter::LINEAR: {
desc.magFilter = wgpu::FilterMode::Linear;
break;
}
}
case SamplerMagFilter::LINEAR: {
desc.magFilter = wgpu::FilterMode::Linear;
break;
}
}
switch (params.filterMin) {
case SamplerMinFilter::NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
switch (params.filterMin) {
case SamplerMinFilter::NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
break;
}
case SamplerMinFilter::LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
// suffice
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
}
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Nearest;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
break;
}
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
}
}
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
break;
}
}
switch (params.compareFunc) {
case SamplerCompareFunc::LE: {
desc.compare = wgpu::CompareFunction::LessEqual;
break;
}
case SamplerCompareFunc::GE: {
desc.compare = wgpu::CompareFunction::GreaterEqual;
break;
}
case SamplerCompareFunc::L: {
desc.compare = wgpu::CompareFunction::Less;
break;
}
case SamplerCompareFunc::G: {
desc.compare = wgpu::CompareFunction::Greater;
break;
}
case SamplerCompareFunc::E: {
desc.compare = wgpu::CompareFunction::Equal;
break;
}
case SamplerCompareFunc::NE: {
desc.compare = wgpu::CompareFunction::NotEqual;
break;
}
case SamplerCompareFunc::A: {
desc.compare = wgpu::CompareFunction::Always;
break;
}
case SamplerCompareFunc::N: {
desc.compare = wgpu::CompareFunction::Never;
break;
switch (params.compareFunc) {
case SamplerCompareFunc::LE: {
desc.compare = wgpu::CompareFunction::LessEqual;
break;
}
case SamplerCompareFunc::GE: {
desc.compare = wgpu::CompareFunction::GreaterEqual;
break;
}
case SamplerCompareFunc::L: {
desc.compare = wgpu::CompareFunction::Less;
break;
}
case SamplerCompareFunc::G: {
desc.compare = wgpu::CompareFunction::Greater;
break;
}
case SamplerCompareFunc::E: {
desc.compare = wgpu::CompareFunction::Equal;
break;
}
case SamplerCompareFunc::NE: {
desc.compare = wgpu::CompareFunction::NotEqual;
break;
}
case SamplerCompareFunc::A: {
desc.compare = wgpu::CompareFunction::Always;
break;
}
case SamplerCompareFunc::N: {
desc.compare = wgpu::CompareFunction::Never;
break;
}
}
}
desc.maxAnisotropy = 1u << params.anisotropyLog2;
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
// Unused: WGPU lodMinClamp/lodMaxClamp
//TODO Once we can properly map to descriptorsetlayout use the sampler.
return mDevice.CreateSampler(/*&desc*/);
return mDevice.CreateSampler(&desc);
}
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
switch (fWrapMode) {
+201 -40
View File
@@ -247,6 +247,7 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
const auto& temp = std::get_if<utils::CString>(&layout.label);
baseLabel = temp->c_str();
}
label = baseLabel;
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
// debugging. For now, hack an incrementing value.
@@ -254,8 +255,7 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
unsigned int samplerCount =
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
return fEntry.type == DescriptorType::SAMPLER ||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
return DescriptorSetLayoutBinding::isSampler(fEntry.type);
});
@@ -269,12 +269,31 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
wEntry.binding = fEntry.binding * 2;
entryInfo.binding = wEntry.binding;
wgpu::BindGroupLayoutEntry* sEntry;
switch (fEntry.type) {
case DescriptorType::SAMPLER_EXTERNAL:
case DescriptorType::SAMPLER: {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT: {
auto& samplerEntry = wEntries.emplace_back();
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
sEntry = &samplerEntry;
samplerEntry.binding = fEntry.binding * 2 + 1;
samplerEntryInfo.binding = samplerEntry.binding;
samplerEntryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER;
@@ -282,15 +301,6 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
// We are simply hoping that undefined and defaults suffices here.
samplerEntry.sampler.type = wgpu::SamplerBindingType::NonFiltering; // Example default
wEntry.texture.sampleType = wgpu::TextureSampleType::Float; // Example default
// TODO: FIX! THIS IS HACK FOR HELLO-TRIANGLE!
if (baseLabel.find("Skybox") != std::string::npos ||
(baseLabel == "Filament Default Material_perView" && wEntry.binding == 22)) {
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
} else {
wEntry.texture.viewDimension =
wgpu::TextureViewDimension::e2D;// Example default
}
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW;
break;
}
case DescriptorType::UNIFORM_BUFFER: {
@@ -310,6 +320,81 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
PANIC_POSTCONDITION("Shader storage is not supported");
break;
}
case DescriptorType::SAMPLER_EXTERNAL: {
PANIC_POSTCONDITION("External Sampler is not supported");
break;
}
}
switch (fEntry.type) {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_2D;
break;
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_2DA;
break;
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_CUBE;
break;
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
wEntry.texture.viewDimension = wgpu::TextureViewDimension::CubeArray;
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_CUBEA;
break;
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e3D;
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_3D;
break;
default:
break;
}
switch (fEntry.type) {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_3D_FLOAT:
wEntry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
break;
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_3D_INT:
wEntry.texture.sampleType = wgpu::TextureSampleType::Sint;
break;
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_3D_UINT:
wEntry.texture.sampleType = wgpu::TextureSampleType::Uint;
break;
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
//Dummies complain if you set this correctly without having an associated dummy
wEntry.texture.sampleType = wgpu::TextureSampleType::Depth;
sEntry->sampler.type = wgpu::SamplerBindingType::Comparison;
break;
default:
break;
}
// fEntry.count is unused currently
}
@@ -325,12 +410,12 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
wgpu::Buffer WebGPUDescriptorSet::sDummyUniformBuffer = nullptr;
wgpu::Texture WebGPUDescriptorSet::sDummyTexture = nullptr;
wgpu::TextureView WebGPUDescriptorSet::sDummyTextureView = nullptr;
std::unordered_map<wgpu::TextureDimension, wgpu::Texture> WebGPUDescriptorSet::sDummyTextureMap;
std::unordered_map<wgpu::TextureViewDimension, wgpu::TextureView> WebGPUDescriptorSet::sDummyTextureViewMap;
wgpu::Sampler WebGPUDescriptorSet::sDummySampler = nullptr;
void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device const& device,
wgpu::TextureFormat aColorFormat) {
wgpu::TextureFormat aColorFormat, wgpu::TextureFormat aDepthFormat) {
if (!sDummyUniformBuffer) {
wgpu::BufferDescriptor bufferDescriptor{
.label = "dummy_uniform_not_to_be_used",
@@ -341,31 +426,75 @@ void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device cons
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
<< "Failed to create dummy uniform buffer?";
}
if (!sDummyTexture || !sDummyTextureView) {
if (sDummyTextureMap.empty() || sDummyTextureViewMap.empty()) {
wgpu::TextureDescriptor textureDescriptor{
.label = "dummy_texture_not_to_be_used",
.usage = wgpu::TextureUsage::TextureBinding,
.dimension = wgpu::TextureDimension::e2D,
.size = wgpu::Extent3D{ .width = 4, .height = 4, .depthOrArrayLayers = 1 },
.format = aColorFormat,
// .viewFormatCount = 1,
// .viewFormats = &aDepthFormat
};
if (!sDummyTexture) {
sDummyTexture = device.CreateTexture(&textureDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy texture?";
}
if (!sDummyTextureView) {
wgpu::TextureViewDescriptor textureViewDescriptor{
.label = "dummy_texture_view_not_to_be_used"
};
sDummyTextureView = sDummyTexture.CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
<< "Failed to create dummy texture view?";
}
sDummyTextureMap[wgpu::TextureDimension::e2D] = device.CreateTexture(&textureDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureMap[wgpu::TextureDimension::e2D])
<< "Failed to create dummy texture 2D?";
textureDescriptor.dimension = wgpu::TextureDimension::e3D;
sDummyTextureMap[wgpu::TextureDimension::e3D] = device.CreateTexture(&textureDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureMap[wgpu::TextureDimension::e3D])
<< "Failed to create dummy texture 3D?";
//Hacking as an experiment, treating 1D as cube arbitrarilly since my map key was bad idea
textureDescriptor.dimension = wgpu::TextureDimension::e2D;
textureDescriptor.size.depthOrArrayLayers = 6;
sDummyTextureMap[wgpu::TextureDimension::e1D] = device.CreateTexture(&textureDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureMap[wgpu::TextureDimension::e1D])
<< "Failed to create dummy texture 3D?";
wgpu::TextureViewDescriptor textureViewDescriptor{
.label = "dummy_texture_view_not_to_be_used",
};
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
sDummyTextureViewMap[wgpu::TextureViewDimension::e2D] =
sDummyTextureMap[wgpu::TextureDimension::e2D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::e2D])
<< "Failed to create dummy texture view?";
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
sDummyTextureViewMap[wgpu::TextureViewDimension::e2DArray] =
sDummyTextureMap[wgpu::TextureDimension::e2D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::e2D])
<< "Failed to create dummy texture view?";
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
sDummyTextureViewMap[wgpu::TextureViewDimension::e2DArray] =
sDummyTextureMap[wgpu::TextureDimension::e2D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::e2DArray])
<< "Failed to create dummy texture view?";
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e3D;
sDummyTextureViewMap[wgpu::TextureViewDimension::e3D] =
sDummyTextureMap[wgpu::TextureDimension::e3D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::e3D])
<< "Failed to create dummy texture view?";
textureViewDescriptor.arrayLayerCount = 6;
textureViewDescriptor.dimension = wgpu::TextureViewDimension::Cube;
sDummyTextureViewMap[wgpu::TextureViewDimension::Cube] =
sDummyTextureMap[wgpu::TextureDimension::e1D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::Cube])
<< "Failed to create dummy texture view?";
textureViewDescriptor.dimension = wgpu::TextureViewDimension::CubeArray;
sDummyTextureViewMap[wgpu::TextureViewDimension::CubeArray] =
sDummyTextureMap[wgpu::TextureDimension::e1D].CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyTextureViewMap[wgpu::TextureViewDimension::CubeArray])
<< "Failed to create dummy texture view?";
}
if (!sDummySampler) {
wgpu::SamplerDescriptor samplerDescriptor{
.label = "dummy_sampler_not_to_be_used"
};
wgpu::SamplerDescriptor samplerDescriptor{ .label = "dummy_sampler_not_to_be_used" , .addressModeU = wgpu::AddressMode::MirrorRepeat};
sDummySampler = device.CreateSampler(&samplerDescriptor);
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy sampler?";
}
@@ -377,12 +506,12 @@ std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedB
assert_invariant(WebGPUDescriptorSet::sDummyUniformBuffer &&
"Dummy uniform buffer must have been created before "
"creating dummy bind group entries.");
assert_invariant(
/* assert_invariant(
WebGPUDescriptorSet::sDummyTexture &&
"Dummy texture must have been created before creating dummy bind group entries.");
assert_invariant(
WebGPUDescriptorSet::sDummyTextureView &&
"Dummy texture view must have been created before creating dummy bind group entries.");
"Dummy texture view must have been created before creating dummy bind group entries.");*/
assert_invariant(
WebGPUDescriptorSet::sDummySampler &&
"Dummy sampler must have been created before creating dummy bind group entries.");
@@ -394,14 +523,31 @@ std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedB
entry.binding = entryInfo.binding;
switch (entryInfo.type) {
case WebGPUDescriptorSetLayout::BindGroupEntryType::UNIFORM_BUFFER:
entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW:
entry.textureView = WebGPUDescriptorSet::sDummyTextureView;
//entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER:
entry.sampler = WebGPUDescriptorSet::sDummySampler;
// entry.sampler = WebGPUDescriptorSet::sDummySampler;
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_2D:
// entry.textureView = WebGPUDescriptorSet::sDummyTextureViewMap[wgpu::TextureViewDimension::e2D];
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_2DA:
// entry.textureView = WebGPUDescriptorSet::sDummyTextureViewMap[wgpu::TextureViewDimension::e2DArray];
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_CUBE:
// entry.textureView = WebGPUDescriptorSet::sDummyTextureViewMap[wgpu::TextureViewDimension::Cube];
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_CUBEA:
// entry.textureView = WebGPUDescriptorSet::sDummyTextureViewMap[wgpu::TextureViewDimension::CubeArray];
break;
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW_3D:
// entry.textureView = WebGPUDescriptorSet::sDummyTextureViewMap[wgpu::TextureViewDimension::e3D];
break;
default: break;
}
}
std::sort(entries.begin(), entries.end(),
@@ -412,9 +558,10 @@ std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedB
}
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries, std::string label)
: mLayout(layout),
mEntriesSortedByBinding(createDummyEntriesSortedByBinding(bindGroupEntries)) {
bglLabel = label;
// Establish the size of entries based on the layout. This should be reliable and efficient.
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
@@ -449,6 +596,20 @@ wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
.entryCount = mEntriesSortedByBinding.size(),
.entries = mEntriesSortedByBinding.data()
};
for(auto e : mEntriesSortedByBinding){
if(e.sampler.Get() == sDummySampler.Get()){
printf("===R Dummy %s UBO %i\n", bglLabel.c_str(), e.binding/2);
}
for(auto dt : sDummyTextureViewMap){
if(e.textureView.Get() == dt.second.Get())
{
printf("===R Dummy %s Tex %i\n", bglLabel.c_str(), e.binding/2);
}
}
if(e.buffer.Get() == sDummyUniformBuffer.Get()){
printf("===R Dummy %s Sam %i\n", bglLabel.c_str(),(e.binding-1)/2);
}
}
mBindGroup = device.CreateBindGroup(&desc);
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
// once we have created the bind group itself we should no longer need any other state
+12 -5
View File
@@ -103,10 +103,15 @@ struct WGPUBufferObject : HwBufferObject {
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
public:
std::string label;
enum class BindGroupEntryType : uint8_t {
UNIFORM_BUFFER,
TEXTURE_VIEW,
TEXTURE_VIEW_2D,
TEXTURE_VIEW_2DA,
TEXTURE_VIEW_CUBE,
TEXTURE_VIEW_CUBEA,
TEXTURE_VIEW_3D,
SAMPLER
};
@@ -133,11 +138,13 @@ private:
class WebGPUDescriptorSet final : public HwDescriptorSet {
public:
std::string bglLabel;
static void initializeDummyResourcesIfNotAlready(wgpu::Device const&,
wgpu::TextureFormat aColorFormat);
wgpu::TextureFormat aColorFormat,
wgpu::TextureFormat aDepthFormat);
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries, std::string label);
~WebGPUDescriptorSet();
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
@@ -148,8 +155,8 @@ public:
private:
static wgpu::Buffer sDummyUniformBuffer;
static wgpu::Texture sDummyTexture;
static wgpu::TextureView sDummyTextureView;
static std::unordered_map<wgpu::TextureDimension, wgpu::Texture> sDummyTextureMap;
static std::unordered_map<wgpu::TextureViewDimension, wgpu::TextureView> sDummyTextureViewMap;
static wgpu::Sampler sDummySampler;
static std::vector<wgpu::BindGroupEntry> createDummyEntriesSortedByBinding(
@@ -17,6 +17,7 @@
#include "ShaderGenerator.h"
#include <GlslangToSpv.h>
#include <SPVRemapper.h>
#include <spirv_glsl.hpp>
#include <spirv_msl.hpp>
+1 -1
View File
@@ -184,7 +184,7 @@ std::vector<UniformConfig> GetUniformConfig(ShaderUniformType type) {
"backend_test", "test_tex", 0,
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
return {{
"test_tex", DescriptorType::SAMPLER, samplerInfo
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
}};
}
default:
+1 -1
View File
@@ -118,7 +118,7 @@ TEST_F(BackendTest, FeedbackLoops) {
Shader shader = Shader(api, cleanup, ShaderConfig {
.vertexShader = fullscreenVs,
.fragmentShader = fullscreenFs,
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}, {"Params"}}
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}, {"Params"}}
});
TrianglePrimitive const triangle(getDriverApi());
+4 -4
View File
@@ -308,7 +308,7 @@ TEST_F(LoadImageTest, UpdateImage2D) {
Shader shader(api, cleanup, ShaderConfig{
.vertexShader = mVertexShader,
.fragmentShader= fragment,
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}}
});
// Create a Texture.
@@ -372,7 +372,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
getSamplerTypeName(textureFormat), fragmentTemplate);
Shader shader(api, cleanup, ShaderConfig{
.vertexShader = mVertexShader, .fragmentShader = fragment, .uniforms = {{
"test_tex", DescriptorType::SAMPLER, samplerInfo
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
}}});
// Create a texture.
@@ -447,7 +447,7 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
Shader shader(api, cleanup, ShaderConfig {
.vertexShader = mVertexShader,
.fragmentShader = fragment,
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}}
});
// Create a texture with 3 mip levels.
@@ -508,7 +508,7 @@ TEST_F(LoadImageTest, UpdateImage3D) {
Shader shader(api, cleanup, ShaderConfig {
.vertexShader = mVertexShader,
.fragmentShader = fragment,
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_ARRAY_FLOAT, samplerInfo}}
});
// Create a texture.
+1 -1
View File
@@ -82,7 +82,7 @@ TEST_F(BackendTest, TextureViewLod) {
.vertexShader = vertexShader,
.fragmentShader = fragmentTexturedLod,
.uniforms = {{
"backend_test_sib_tex", DescriptorType::SAMPLER, samplerInfo
"backend_test_sib_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
}}
});
+119 -5
View File
@@ -21,13 +21,17 @@
#include <filament/FilamentAPI.h>
#include <filament/ToneMapper.h>
#include <filament/ColorSpace.h>
#include <utils/compiler.h>
#include <math/mathfwd.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <stdint.h>
#include <stddef.h>
#include <memory>
namespace filament {
@@ -201,15 +205,14 @@ public:
*
* The default tone mapping operator is ACESLegacyToneMapper.
*
* The specified tone mapper must have a lifecycle that exceeds the lifetime of
* this builder. Since the build(Engine&) method is synchronous, it is safe to
* delete the tone mapper object after that finishes executing.
* The ownership of the specified tone mapper is shared with the builder and built
* ColorGrading object.
*
* @param toneMapper The tone mapping operator to apply to the HDR color buffer
*
* @return This Builder, for chaining calls
*/
Builder& toneMapper(ToneMapper const* UTILS_NULLABLE toneMapper) noexcept;
Builder& toneMapper(std::shared_ptr<ToneMapper> toneMapper) noexcept;
/**
* Selects the tone mapping operator to apply to the HDR color buffer as the last
@@ -487,7 +490,118 @@ public:
friend class FColorGrading;
};
protected:
/** Returns the quality level used to create this ColorGrading object. */
QualityLevel getQuality() const noexcept;
/** Returns the LUT format used to create this ColorGrading object. */
LutFormat getLutFormat() const noexcept;
/** Returns the LUT dimensions used to create this ColorGrading object. */
uint8_t getLutDimensions() const noexcept;
/** Returns the tone mapper used to create this ColorGrading object. */
const ToneMapper& getToneMapper() const noexcept;
/** Returns whether luminance scaling was enabled during creation. */
bool isLuminanceScalingEnabled() const noexcept;
/** Returns whether gamut mapping was enabled during creation. */
bool isGamutMappingEnabled() const noexcept;
/** Returns the exposure value used to create this ColorGrading object. */
float getExposure() const noexcept;
/** Returns the night adaptation value used to create this ColorGrading object. */
float getNightAdaptation() const noexcept;
/** Returns the white balance temperature used to create this ColorGrading object. */
float getWhiteBalanceTemperature() const noexcept;
/** Returns the white balance tint used to create this ColorGrading object. */
float getWhiteBalanceTint() const noexcept;
/** Returns the channel mixer output for the red channel. */
math::float3 getChannelMixerOutRed() const noexcept;
/** Returns the channel mixer output for the green channel. */
math::float3 getChannelMixerOutGreen() const noexcept;
/** Returns the channel mixer output for the blue channel. */
math::float3 getChannelMixerOutBlue() const noexcept;
/** Returns the shadows adjustment used to create this ColorGrading object. */
math::float3 getShadows() const noexcept;
/** Returns the midtones adjustment used to create this ColorGrading object. */
math::float3 getMidtones() const noexcept;
/** Returns the highlights adjustment used to create this ColorGrading object. */
math::float3 getHighlights() const noexcept;
/** Returns the shadow/midtones/highlights ranges used to create this ColorGrading object. */
math::float4 getShadowMidtonesHighlightsRanges() const noexcept;
/** Returns the slope adjustment used to create this ColorGrading object. */
math::float3 getSlope() const noexcept;
/** Returns the offset adjustment used to create this ColorGrading object. */
math::float3 getOffset() const noexcept;
/** Returns the power adjustment used to create this ColorGrading object. */
math::float3 getPower() const noexcept;
/** Returns the contrast value used to create this ColorGrading object. */
float getContrast() const noexcept;
/** Returns the vibrance value used to create this ColorGrading object. */
float getVibrance() const noexcept;
/** Returns the saturation value used to create this ColorGrading object. */
float getSaturation() const noexcept;
/** Returns the shadow gamma curve adjustment used to create this ColorGrading object. */
math::float3 getCurvesShadowGamma() const noexcept;
/** Returns the mid-point curve adjustment used to create this ColorGrading object. */
math::float3 getCurvesMidPoint() const noexcept;
/** Returns the highlight scale curve adjustment used to create this ColorGrading object. */
math::float3 getCurvesHighlightScale() const noexcept;
/** Returns the output color space used to create this ColorGrading object. */
const color::ColorSpace& getOutputColorSpace() const noexcept;
protected :
struct Settings {
LutFormat lutFormat = LutFormat::INTEGER;
uint8_t lutDimensions = 32;
std::shared_ptr<ToneMapper> toneMapper = std::make_shared<ACESLegacyToneMapper>();
bool luminanceScaling = false;
bool gummapMapping = false;
float exposure = 0.0f;
float nightAdaptation = 0.0f;
float whiteBalanceTemperature = 0.0f;
float whiteBalanceTint = 0.0f;
math::float3 channelMixerOutRed{1.0f, 0.0f, 0.0f};
math::float3 channelMixerOutGreen{0.0f, 1.0f, 0.0f};
math::float3 channelMixerOutBlue{0.0f, 0.0f, 1.0f};
math::float3 shadows{1.0f, 1.0f, 1.0f};
math::float3 midtones{1.0f, 1.0f, 1.0f};
math::float3 highlights{1.0f, 1.0f, 1.0f};
math::float4 ShadowMidtonesHighlightsRanges{0.0f, 0.333f, 0.55f, 1.0f};
math::float3 slope{1.0f};
math::float3 offset{0.0f};
math::float3 power{1.0f};
float contrast = 1.0f;
float vibrance = 1.0f;
float saturation = 1.0f;
math::float3 curvesShadowGamma{1.0f, 1.0f, 1.0f};
math::float3 curvesMidPoint{1.0f, 1.0f, 1.0f};
math::float3 curvesHighlightScale{1.0f, 1.0f, 1.0f};
color::ColorSpace colorSpace = color::Rec709 - color::sRGB - color::D65;
};
Settings mSettings;
// prevent heap allocation
~ColorGrading() = default;
};
-9
View File
@@ -317,15 +317,6 @@ public:
*/
size_t metalUploadBufferSizeBytes = 512 * 1024;
/**
* The action to take if a Drawable cannot be acquired.
*
* Each frame rendered requires a CAMetalDrawable texture, which is
* presented on-screen at the completion of each frame. These are
* limited and provided round-robin style by the system.
*/
bool metalDisablePanicOnDrawableFailure = false;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
+26 -2
View File
@@ -54,6 +54,8 @@ namespace filament {
struct UTILS_PUBLIC ToneMapper {
ToneMapper() noexcept;
virtual ~ToneMapper() noexcept;
ToneMapper(ToneMapper const&) noexcept;
ToneMapper& operator=(ToneMapper const&) noexcept = default;
/**
* Maps an open domain (or "scene referred" values) color value to display
@@ -69,6 +71,13 @@ struct UTILS_PUBLIC ToneMapper {
*/
virtual math::float3 operator()(math::float3 c) const noexcept = 0;
/**
* Creates a copy of this tone mapper instance.
*
* @return A pointer to a new ToneMapper instance that is a copy of this instance.
*/
virtual ToneMapper* clone() const noexcept = 0;
/**
* If true, then this function holds that f(x) = vec3(f(x.r), f(x.g), f(x.b))
*
@@ -92,8 +101,10 @@ struct UTILS_PUBLIC ToneMapper {
struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper {
LinearToneMapper() noexcept;
~LinearToneMapper() noexcept final;
LinearToneMapper(LinearToneMapper const&) noexcept;
math::float3 operator()(math::float3 c) const noexcept override;
LinearToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return true; }
};
@@ -106,8 +117,10 @@ struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper {
struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper {
ACESToneMapper() noexcept;
~ACESToneMapper() noexcept final;
ACESToneMapper(ACESToneMapper const&) noexcept;
math::float3 operator()(math::float3 c) const noexcept override;
ACESToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
@@ -121,8 +134,10 @@ struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper {
struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper {
ACESLegacyToneMapper() noexcept;
~ACESLegacyToneMapper() noexcept final;
ACESLegacyToneMapper(ACESLegacyToneMapper const&) noexcept;
math::float3 operator()(math::float3 c) const noexcept override;
ACESLegacyToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
@@ -136,8 +151,10 @@ struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper {
struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
FilmicToneMapper() noexcept;
~FilmicToneMapper() noexcept final;
FilmicToneMapper(FilmicToneMapper const&) noexcept;
math::float3 operator()(math::float3 x) const noexcept override;
FilmicToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return false; }
};
@@ -150,8 +167,10 @@ struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
struct UTILS_PUBLIC PBRNeutralToneMapper final : public ToneMapper {
PBRNeutralToneMapper() noexcept;
~PBRNeutralToneMapper() noexcept final;
PBRNeutralToneMapper(PBRNeutralToneMapper const&) noexcept;
math::float3 operator()(math::float3 x) const noexcept override;
virtual PBRNeutralToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
@@ -173,8 +192,10 @@ struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper {
*/
explicit AgxToneMapper(AgxLook look = AgxLook::NONE) noexcept;
~AgxToneMapper() noexcept final;
AgxToneMapper(AgxToneMapper const&) noexcept;
math::float3 operator()(math::float3 x) const noexcept override;
virtual AgxToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
@@ -215,12 +236,13 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
) noexcept;
~GenericToneMapper() noexcept final;
GenericToneMapper(GenericToneMapper const&) = delete;
GenericToneMapper& operator=(GenericToneMapper const&) = delete;
GenericToneMapper(GenericToneMapper const& rhs) noexcept;
GenericToneMapper& operator=(GenericToneMapper const& rhs) noexcept;
GenericToneMapper(GenericToneMapper&& rhs) noexcept;
GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept;
math::float3 operator()(math::float3 x) const noexcept override;
GenericToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return false; }
@@ -283,8 +305,10 @@ private:
struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper {
DisplayRangeToneMapper() noexcept;
~DisplayRangeToneMapper() noexcept override;
DisplayRangeToneMapper(DisplayRangeToneMapper const&) noexcept;
math::float3 operator()(math::float3 c) const noexcept override;
DisplayRangeToneMapper* clone() const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
+4 -3
View File
@@ -232,7 +232,7 @@ PostProcessManager::~PostProcessManager() noexcept = default;
void PostProcessManager::setFrameUniforms(DriverApi& driver,
TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
mPostProcessDescriptorSet.setFrameUniforms(driver, uniforms);
mSsrPassDescriptorSet.setFrameUniforms(uniforms);
mSsrPassDescriptorSet.setFrameUniforms(mEngine, uniforms);
}
void PostProcessManager::bindPostProcessDescriptorSet(DriverApi& driver) const noexcept {
@@ -504,6 +504,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
if (config.picking) {
// FIXME: the DescriptorSetLayout must specify SAMPLER_FLOAT
data.picking = builder.createTexture("Picking Buffer", {
.width = width, .height = height,
.format = isES2 ? TextureFormat::RGBA8 : TextureFormat::RG32F });
@@ -653,7 +654,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
options, passBuilder = passBuilder]
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
// set structure sampler
mSsrPassDescriptorSet.prepareStructure(data.structure ?
mSsrPassDescriptorSet.prepareStructure(mEngine, data.structure ?
resources.getTexture(data.structure) : getOneTexture());
// set screen-space reflections and screen-space refractions
@@ -664,7 +665,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
// the history sampler is a regular texture2D
TextureHandle const history = data.history ?
resources.getTexture(data.history) : getZeroTexture();
mSsrPassDescriptorSet.prepareHistorySSR(history, reprojection, uvFromViewMatrix, options);
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history, reprojection, uvFromViewMatrix, options);
mSsrPassDescriptorSet.commit(mEngine);
+13 -2
View File
@@ -921,7 +921,6 @@ backend::Viewport RenderPass::Executor::applyScissorViewport(
UTILS_NOINLINE // no need to be inlined
void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
Command const* first, Command const* last) const noexcept {
SYSTRACE_CALL();
SYSTRACE_CONTEXT();
@@ -942,6 +941,13 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
driver.scissor(mScissor);
}
// If we have a mColorPassDescriptorSet, we need to use its idea of "VSM" to select
// the descriptor set layout. Materials always offer both.
// If we don't have a mColorPassDescriptorSet, it doesn't matter because the layout
// are chosen via the variant only.
bool const useVsmDescriptorSetLayout =
mColorPassDescriptorSet ? mColorPassDescriptorSet->isVSM() : false;
bool const polygonOffsetOverride = mPolygonOffsetOverride;
PipelineState pipeline{
// initialize with polygon offset override
@@ -1051,8 +1057,13 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
// Each material has its own version of the per-view descriptor-set layout,
// because it depends on the material features (e.g. lit/unlit)
// TODO: QUESTION: are
// Variant::isValidDepthVariant(info.materialVariant) and
// Variant::isSSRVariant(info.materialVariant)
// constant? If so we could precompute ma->getPerViewDescriptorSetLayout()
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_VIEW] =
ma->getPerViewDescriptorSetLayout(info.materialVariant).getHandle();
ma->getPerViewDescriptorSetLayout(info.materialVariant,
useVsmDescriptorSetLayout).getHandle();
// Each material has a per-material descriptor-set layout which encodes the
// material's parameters (ubo and samplers)
+4 -2
View File
@@ -205,11 +205,13 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
view.prepareSSAO(data.ssao ?
resources.getTexture(data.ssao) : engine.getOneTextureArray());
view.prepareShadowMapping(view.getVsmShadowOptions().highPrecision);
view.prepareShadowMapping(engine, view.getVsmShadowOptions().highPrecision);
// set shadow sampler
view.prepareShadow(data.shadows ?
resources.getTexture(data.shadows) : engine.getOneTextureArray());
resources.getTexture(data.shadows) :
(view.getShadowType() != ShadowType::PCF ?
engine.getOneTextureArray() : engine.getOneTextureArrayDepth()));
// set structure sampler
view.prepareStructure(data.structure ?
+48 -2
View File
@@ -188,7 +188,8 @@ float3 ACES(float3 color, float brightness) noexcept {
#define DEFAULT_CONSTRUCTORS(A) \
A::A() noexcept = default; \
A::~A() noexcept = default;
A::~A() noexcept = default; \
A::A(A const&) noexcept = default;
DEFAULT_CONSTRUCTORS(ToneMapper)
@@ -202,6 +203,10 @@ float3 LinearToneMapper::operator()(float3 const v) const noexcept {
return saturate(v);
}
LinearToneMapper* LinearToneMapper::clone() const noexcept {
return new LinearToneMapper(*this);
}
//------------------------------------------------------------------------------
// ACES tone mappers
//------------------------------------------------------------------------------
@@ -212,12 +217,20 @@ float3 ACESToneMapper::operator()(float3 const c) const noexcept {
return aces::ACES(c, 1.0f);
}
ACESToneMapper* ACESToneMapper::clone() const noexcept {
return new ACESToneMapper(*this);
}
DEFAULT_CONSTRUCTORS(ACESLegacyToneMapper)
float3 ACESLegacyToneMapper::operator()(float3 const c) const noexcept {
return aces::ACES(c, 1.0f / 0.6f);
}
ACESLegacyToneMapper* ACESLegacyToneMapper::clone() const noexcept {
return new ACESLegacyToneMapper(*this);
}
DEFAULT_CONSTRUCTORS(FilmicToneMapper)
float3 FilmicToneMapper::operator()(float3 const x) const noexcept {
@@ -230,6 +243,10 @@ float3 FilmicToneMapper::operator()(float3 const x) const noexcept {
return (x * (a * x + b)) / (x * (c * x + d) + e);
}
FilmicToneMapper* FilmicToneMapper::clone() const noexcept {
return new FilmicToneMapper(*this);
}
//------------------------------------------------------------------------------
// PBR Neutral tone mapper
//------------------------------------------------------------------------------
@@ -256,12 +273,17 @@ float3 PBRNeutralToneMapper::operator()(float3 color) const noexcept {
return mix(color, float3(newPeak), g);
}
PBRNeutralToneMapper* PBRNeutralToneMapper::clone() const noexcept {
return new PBRNeutralToneMapper(*this);
}
//------------------------------------------------------------------------------
// AgX tone mapper
//------------------------------------------------------------------------------
AgxToneMapper::AgxToneMapper(AgxLook const look) noexcept : look(look) {}
AgxToneMapper::~AgxToneMapper() noexcept = default;
AgxToneMapper::AgxToneMapper(AgxToneMapper const& rhs) noexcept = default;
// These matrices taken from Blender's implementation of AgX, which works with Rec.2020 primaries.
// https://github.com/EaryChow/AgX_LUT_Gen/blob/main/AgXBaseRec2020.py
@@ -356,6 +378,10 @@ float3 AgxToneMapper::operator()(float3 v) const noexcept {
return v;
}
AgxToneMapper* AgxToneMapper::clone() const noexcept {
return new AgxToneMapper(*this);
}
//------------------------------------------------------------------------------
// Display range tone mapper
//------------------------------------------------------------------------------
@@ -394,6 +420,10 @@ float3 DisplayRangeToneMapper::operator()(float3 const c) const noexcept {
return mix(debugColors[index], debugColors[index + 1], saturate(v - float(index)));
}
DisplayRangeToneMapper* DisplayRangeToneMapper::clone() const noexcept {
return new DisplayRangeToneMapper(*this);
}
//------------------------------------------------------------------------------
// Generic tone mapper
//------------------------------------------------------------------------------
@@ -454,7 +484,19 @@ GenericToneMapper::~GenericToneMapper() noexcept {
delete mOptions;
}
GenericToneMapper::GenericToneMapper(GenericToneMapper&& rhs) noexcept : mOptions(rhs.mOptions) {
GenericToneMapper::GenericToneMapper(GenericToneMapper const& rhs) noexcept {
mOptions = new Options(*rhs.mOptions);
}
GenericToneMapper& GenericToneMapper::operator=(GenericToneMapper const& rhs) noexcept {
if (this != &rhs) {
delete mOptions;
mOptions = new Options(*rhs.mOptions);
}
return *this;
}
GenericToneMapper::GenericToneMapper(GenericToneMapper&& rhs) noexcept : mOptions(rhs.mOptions) {
rhs.mOptions = nullptr;
}
@@ -469,6 +511,10 @@ float3 GenericToneMapper::operator()(float3 x) const noexcept {
return mOptions->outputScale * x / (x + mOptions->inputScale);
}
GenericToneMapper* GenericToneMapper::clone() const noexcept {
return new GenericToneMapper(*this);
}
float GenericToneMapper::getContrast() const noexcept { return mOptions->contrast; }
float GenericToneMapper::getMidGrayIn() const noexcept { return mOptions->midGrayIn; }
float GenericToneMapper::getMidGrayOut() const noexcept { return mOptions->midGrayOut; }
+143 -12
View File
@@ -49,7 +49,7 @@ using namespace backend;
//------------------------------------------------------------------------------
struct ColorGrading::BuilderDetails {
const ToneMapper* toneMapper = nullptr;
std::shared_ptr<ToneMapper> toneMapper = nullptr;
#if defined(__clang__)
#pragma clang diagnostic push
@@ -173,7 +173,7 @@ ColorGrading::Builder& ColorGrading::Builder::dimensions(uint8_t const dim) noex
return *this;
}
ColorGrading::Builder& ColorGrading::Builder::toneMapper(const ToneMapper* toneMapper) noexcept {
ColorGrading::Builder& ColorGrading::Builder::toneMapper(std::shared_ptr<ToneMapper> toneMapper) noexcept {
mImpl->toneMapper = toneMapper;
return *this;
}
@@ -271,6 +271,110 @@ ColorGrading::Builder& ColorGrading::Builder::outputColorSpace(
return *this;
}
ColorGrading::LutFormat ColorGrading::getLutFormat() const noexcept {
return mSettings.lutFormat;
}
uint8_t ColorGrading::getLutDimensions() const noexcept {
return mSettings.lutDimensions;
}
const ToneMapper& ColorGrading::getToneMapper() const noexcept {
return *mSettings.toneMapper;
}
bool ColorGrading::isLuminanceScalingEnabled() const noexcept {
return mSettings.luminanceScaling;
}
bool ColorGrading::isGamutMappingEnabled() const noexcept {
return mSettings.gummapMapping;
}
float ColorGrading::getExposure() const noexcept {
return mSettings.exposure;
}
float ColorGrading::getNightAdaptation() const noexcept {
return mSettings.nightAdaptation;
}
float ColorGrading::getWhiteBalanceTemperature() const noexcept {
return mSettings.whiteBalanceTemperature;
}
float ColorGrading::getWhiteBalanceTint() const noexcept {
return mSettings.whiteBalanceTint;
}
math::float3 ColorGrading::getChannelMixerOutRed() const noexcept {
return mSettings.channelMixerOutRed;
}
math::float3 ColorGrading::getChannelMixerOutGreen() const noexcept {
return mSettings.channelMixerOutGreen;
}
math::float3 ColorGrading::getChannelMixerOutBlue() const noexcept {
return mSettings.channelMixerOutBlue;
}
math::float3 ColorGrading::getShadows() const noexcept {
return mSettings.shadows;
}
math::float3 ColorGrading::getMidtones() const noexcept {
return mSettings.midtones;
}
math::float3 ColorGrading::getHighlights() const noexcept {
return mSettings.highlights;
}
math::float4 ColorGrading::getShadowMidtonesHighlightsRanges() const noexcept {
return mSettings.ShadowMidtonesHighlightsRanges;
}
math::float3 ColorGrading::getSlope() const noexcept {
return mSettings.slope;
}
math::float3 ColorGrading::getOffset() const noexcept {
return mSettings.offset;
}
math::float3 ColorGrading::getPower() const noexcept {
return mSettings.power;
}
float ColorGrading::getContrast() const noexcept {
return mSettings.contrast;
}
float ColorGrading::getVibrance() const noexcept {
return mSettings.vibrance;
}
float ColorGrading::getSaturation() const noexcept {
return mSettings.saturation;
}
math::float3 ColorGrading::getCurvesShadowGamma() const noexcept {
return mSettings.curvesShadowGamma;
}
math::float3 ColorGrading::getCurvesMidPoint() const noexcept {
return mSettings.curvesMidPoint;
}
math::float3 ColorGrading::getCurvesHighlightScale() const noexcept {
return mSettings.curvesHighlightScale;
}
const color::ColorSpace& ColorGrading::getOutputColorSpace() const noexcept {
return mSettings.colorSpace;
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -287,30 +391,25 @@ ColorGrading* ColorGrading::Builder::build(Engine& engine) {
if (needToneMapper) {
switch (mImpl->toneMapping) {
case ToneMapping::LINEAR:
mImpl->toneMapper = new LinearToneMapper();
mImpl->toneMapper = std::make_shared<LinearToneMapper>();
break;
case ToneMapping::ACES_LEGACY:
mImpl->toneMapper = new ACESLegacyToneMapper();
mImpl->toneMapper = std::make_shared<ACESLegacyToneMapper>();
break;
case ToneMapping::ACES:
mImpl->toneMapper = new ACESToneMapper();
mImpl->toneMapper = std::make_shared<ACESToneMapper>();
break;
case ToneMapping::FILMIC:
mImpl->toneMapper = new FilmicToneMapper();
mImpl->toneMapper = std::make_shared<FilmicToneMapper>();
break;
case ToneMapping::DISPLAY_RANGE:
mImpl->toneMapper = new DisplayRangeToneMapper();
mImpl->toneMapper = std::make_shared<DisplayRangeToneMapper>();
break;
}
}
FColorGrading* colorGrading = downcast(engine).createColorGrading(*this);
if (needToneMapper) {
delete mImpl->toneMapper;
mImpl->toneMapper = nullptr;
}
return colorGrading;
}
@@ -886,6 +985,9 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
data, lutElementCount * elementSize, format, type,
[](void* buffer, size_t, void*) { free(buffer); }
});
// Initialize settings from builder
initializeSettings(builder, mSettings);
}
FColorGrading::~FColorGrading() noexcept = default;
@@ -895,4 +997,33 @@ void FColorGrading::terminate(FEngine& engine) {
driver.destroyTexture(mLutHandle);
}
void FColorGrading::initializeSettings(const Builder& builder, Settings& settings) noexcept {
settings.lutFormat = builder->format;
settings.lutDimensions = builder->dimension;
settings.toneMapper = builder->toneMapper;
settings.luminanceScaling = builder->luminanceScaling;
settings.gummapMapping = builder->gamutMapping;
settings.exposure = builder->exposure;
settings.nightAdaptation = builder->nightAdaptation;
settings.whiteBalanceTemperature = builder->whiteBalance.x;
settings.whiteBalanceTint = builder->whiteBalance.y;
settings.channelMixerOutRed = builder->outRed;
settings.channelMixerOutGreen = builder->outGreen;
settings.channelMixerOutBlue = builder->outBlue;
settings.shadows = builder->shadows;
settings.midtones = builder->midtones;
settings.highlights = builder->highlights;
settings.ShadowMidtonesHighlightsRanges = builder->tonalRanges;
settings.slope = builder->slope;
settings.offset = builder->offset;
settings.power = builder->power;
settings.contrast = builder->contrast;
settings.vibrance = builder->vibrance;
settings.saturation = builder->saturation;
settings.curvesShadowGamma = builder->shadowGamma;
settings.curvesMidPoint = builder->midPoint;
settings.curvesHighlightScale = builder->highlightScale;
settings.colorSpace = builder->outputColorSpace;
}
} //namespace filament
+2
View File
@@ -51,6 +51,8 @@ private:
uint32_t mDimension;
bool mIsOneDimensional;
bool mIsLDR;
static void initializeSettings(const Builder& builder, Settings& settings) noexcept;
};
FILAMENT_DOWNCAST(ColorGrading)
+30 -15
View File
@@ -138,7 +138,6 @@ Engine* FEngine::create(Builder const& builder) {
.forceGLES2Context = instance->getConfig().forceGLES2Context,
.stereoscopicType = instance->getConfig().stereoscopicType,
.assertNativeWindowIsValid = instance->features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = instance->getConfig().metalDisablePanicOnDrawableFailure,
};
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
@@ -362,8 +361,6 @@ void FEngine::init() {
}
// initialize the dummy textures so that their contents are not undefined
static constexpr uint32_t zeroes[6] = {};
static constexpr uint32_t ones = 0xffffffff;
mDefaultIblTexture = downcast(Texture::Builder()
.width(1).height(1).levels(1)
@@ -372,7 +369,8 @@ void FEngine::init() {
.build(*this));
driverApi.update3DImage(mDefaultIblTexture->getHwHandle(), 0, 0, 0, 0, 1, 1, 6,
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
{ std::array<uint8_t, 6>{}.data(), 6,
Texture::Format::RGBA, Texture::Type::UBYTE });
// 3 bands = 9 float3
constexpr float sh[9 * 3] = { 0.0f };
@@ -394,10 +392,12 @@ void FEngine::init() {
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
driverApi.update3DImage(mDummyOneTexture, 0, 0, 0, 0, 1, 1, 1,
{ &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
{ std::array<uint8_t, 4>{0xff, 0xff, 0xff, 0xff}.data(), 4,
Texture::Format::RGBA, Texture::Type::UBYTE });
driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1,
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
{ std::array<uint8_t, 4>{}.data(), 4,
Texture::Format::RGBA, Texture::Type::UBYTE });
mPerViewDescriptorSetLayoutSsrVariant = {
@@ -424,25 +424,28 @@ void FEngine::init() {
} else
#endif
{
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
switch (mConfig.stereoscopicType) {
case StereoscopicType::NONE:
case StereoscopicType::INSTANCED:
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
break;
case StereoscopicType::MULTIVIEW:
#ifdef FILAMENT_ENABLE_MULTIVIEW
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_DATA, MATERIALS_DEFAULTMATERIAL_MULTIVIEW_SIZE);
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_DATA,
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_SIZE);
#else
assert_invariant(false);
#endif
break;
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
}
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
constexpr float3 dummyPositions[1] = {};
constexpr short4 dummyTangents[1] = {};
@@ -452,14 +455,26 @@ void FEngine::init() {
mDummyOneTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
mDummyOneTextureArrayDepth = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
TextureFormat::DEPTH32F, 1, 1, 1, 1, TextureUsage::DEFAULT);
mDummyZeroTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
driverApi.update3DImage(mDummyOneTextureArray, 0, 0, 0, 0, 1, 1, 1,
{ &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
{ std::array<uint8_t, 4>{0xff, 0xff, 0xff, 0xff}.data(), 4,
Texture::Format::RGBA, Texture::Type::UBYTE });
driverApi.update3DImage(mDummyOneTextureArrayDepth, 0, 0, 0, 0, 1, 1, 1,
{ std::array<float, 1>{1.0f}.data(), 4,
Texture::Format::DEPTH_COMPONENT, Texture::Type::FLOAT });
driverApi.update3DImage(mDummyZeroTextureArray, 0, 0, 0, 0, 1, 1, 1,
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
{ std::array<uint8_t, 4>{}.data(), 4,
Texture::Format::RGBA, Texture::Type::UBYTE });
mDummyUniformBuffer = driverApi.createBufferObject(CONFIG_MINSPEC_UBO_SIZE,
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
mLightManager.init(*this);
mDFG.init(*this);
@@ -609,6 +624,8 @@ void FEngine::shutdown() {
driver.destroyTexture(std::move(mDummyZeroTexture));
driver.destroyTexture(std::move(mDummyZeroTextureArray));
driver.destroyBufferObject(std::move(mDummyUniformBuffer));
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
/*
@@ -713,8 +730,7 @@ int FEngine::loop() {
if (mPlatform == nullptr) {
mPlatform = PlatformFactory::create(&mBackend);
mOwnPlatform = true;
const char* const backend = backendToString(mBackend);
slog.i << "FEngine resolved backend: " << backend << io::endl;
slog.i << "FEngine resolved backend: " << to_string(mBackend) << io::endl;
if (mPlatform == nullptr) {
slog.e << "Selected backend not supported in this build." << io::endl;
mDriverBarrier.latch();
@@ -734,7 +750,6 @@ int FEngine::loop() {
.forceGLES2Context = mConfig.forceGLES2Context,
.stereoscopicType = mConfig.stereoscopicType,
.assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = mConfig.metalDisablePanicOnDrawableFailure,
};
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
+25 -4
View File
@@ -486,10 +486,29 @@ public:
return mPerRenderableDescriptorSetLayout;
}
backend::Handle<backend::HwTexture> getOneTexture() const { return mDummyOneTexture; }
backend::Handle<backend::HwTexture> getZeroTexture() const { return mDummyZeroTexture; }
backend::Handle<backend::HwTexture> getOneTextureArray() const { return mDummyOneTextureArray; }
backend::Handle<backend::HwTexture> getZeroTextureArray() const { return mDummyZeroTextureArray; }
backend::Handle<backend::HwTexture> getOneTexture() const {
return mDummyOneTexture;
}
backend::Handle<backend::HwTexture> getOneTextureArray() const {
return mDummyOneTextureArray;
}
backend::Handle<backend::HwTexture> getOneTextureArrayDepth() const {
return mDummyOneTextureArrayDepth;
}
backend::Handle<backend::HwTexture> getZeroTexture() const {
return mDummyZeroTexture;
}
backend::Handle<backend::HwTexture> getZeroTextureArray() const {
return mDummyZeroTextureArray;
}
backend::Handle<backend::HwBufferObject> getDummyUniformBuffer() const {
return mDummyUniformBuffer;
}
static constexpr size_t MiB = 1024u * 1024u;
size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; }
@@ -628,8 +647,10 @@ private:
backend::Handle<backend::HwTexture> mDummyOneTexture;
backend::Handle<backend::HwTexture> mDummyOneTextureArray;
backend::Handle<backend::HwTexture> mDummyOneTextureArrayDepth;
backend::Handle<backend::HwTexture> mDummyZeroTextureArray;
backend::Handle<backend::HwTexture> mDummyZeroTexture;
backend::Handle<backend::HwBufferObject> mDummyUniformBuffer;
std::thread::id mMainThreadId{};
+28 -16
View File
@@ -96,7 +96,7 @@ static std::unique_ptr<MaterialParser> createParser(Backend const backend,
FILAMENT_CHECK_PRECONDITION(
materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND)
<< "the material was not built for any of the " << backendToString(backend)
<< "the material was not built for any of the " << to_string(backend)
<< " backend's supported shader languages (" << languageNames.c_str() << ")\n";
}
@@ -329,11 +329,12 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder,
parser->hasCustomDepthShader(&mHasCustomDepthShader);
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
mIsVariantLit,
mReflectionMode == ReflectionMode::SCREEN_SPACE ||
mRefractionMode == RefractionMode::SCREEN_SPACE,
!(mVariantFilterMask & +UserVariantFilterBit::FOG));
bool const isLit = mIsVariantLit || mHasShadowMultiplier;
bool const isSSR = mReflectionMode == ReflectionMode::SCREEN_SPACE ||
mRefractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(mVariantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(isLit, isSSR, hasFog);
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
@@ -407,6 +408,7 @@ void FMaterial::terminate(FEngine& engine) {
DriverApi& driver = engine.getDriverApi();
mPerViewDescriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
mPerViewDescriptorSetLayoutVsm.terminate(engine.getDescriptorSetLayoutFactory(), driver);
mDescriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
}
@@ -1149,17 +1151,23 @@ void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* con
backend::DescriptorSetLayout descriptorSetLayout;
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
assert_invariant(success);
auto perMatLabel = mName;
perMatLabel.append("_perMat");
descriptorSetLayout.label = std::move(perMatLabel);
// get the PER_VIEW descriptor binding info
auto perViewDescriptorSetLayout =
descriptor_sets::getPerViewDescriptorSetLayout(mMaterialDomain, mVariantFilterMask,
mIsVariantLit || mHasShadowMultiplier, mReflectionMode, mRefractionMode);
auto perViewLabel = mName;
perViewLabel.append("_perView");
perViewDescriptorSetLayout.label = std::move(perViewLabel);
bool const isLit = mIsVariantLit || mHasShadowMultiplier;
bool const isSSR = mReflectionMode == ReflectionMode::SCREEN_SPACE ||
mRefractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(mVariantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
auto perViewDescriptorSetLayout = descriptor_sets::getPerViewDescriptorSetLayout(
mMaterialDomain, isLit, isSSR, hasFog, false);
auto perViewDescriptorSetLayoutVsm = descriptor_sets::getPerViewDescriptorSetLayout(
mMaterialDomain, isLit, isSSR, hasFog, true);
// set the labels
descriptorSetLayout.label = CString{ mName }.append("_perMat");
perViewDescriptorSetLayout.label = CString{ mName }.append("_perView");
perViewDescriptorSetLayoutVsm.label = CString{ mName }.append("_perViewVsm");
// get the PER_RENDERABLE and PER_VIEW descriptor binding info
for (auto&& [bindingPoint, descriptorSetLayout] : {
@@ -1181,7 +1189,11 @@ void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* con
mPerViewDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), perViewDescriptorSetLayout };
engine.getDriverApi(), std::move(perViewDescriptorSetLayout) };
mPerViewDescriptorSetLayoutVsm = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(perViewDescriptorSetLayoutVsm) };
}
descriptor_binding_t FMaterial::getSamplerBinding(
+7 -1
View File
@@ -93,7 +93,8 @@ public:
return mPerViewDescriptorSetLayout;
}
DescriptorSetLayout const& getPerViewDescriptorSetLayout(Variant const variant) const noexcept {
DescriptorSetLayout const& getPerViewDescriptorSetLayout(
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept {
if (Variant::isValidDepthVariant(variant)) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mEngine.getPerViewDescriptorSetLayoutDepthVariant();
@@ -102,6 +103,10 @@ public:
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mEngine.getPerViewDescriptorSetLayoutSsrVariant();
}
if (useVsmDescriptorSetLayout) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mPerViewDescriptorSetLayoutVsm;
}
return mPerViewDescriptorSetLayout;
}
@@ -312,6 +317,7 @@ private:
// try to order by frequency of use
mutable std::array<backend::Handle<backend::HwProgram>, VARIANT_COUNT> mCachedPrograms;
DescriptorSetLayout mPerViewDescriptorSetLayout;
DescriptorSetLayout mPerViewDescriptorSetLayoutVsm;
DescriptorSetLayout mDescriptorSetLayout;
backend::Program::DescriptorSetInfo mProgramDescriptorBindings;
+62 -38
View File
@@ -50,6 +50,8 @@
#include <string_view>
#include <utility>
#include <stddef.h>
using namespace filament::math;
using namespace utils;
@@ -74,15 +76,17 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
FEngine::DriverApi& driver = engine.getDriverApi();
if (!material->getUniformInterfaceBlock().isEmpty()) {
mUniforms = UniformBuffer(material->getUniformInterfaceBlock().getSize());
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
}
// even if the material doesn't have any parameters, we allocate a small UBO because it's
// expected by the per-material descriptor-set layout
size_t const uboSize = std::max(size_t(16), material->getUniformInterfaceBlock().getSize());
mUniforms = UniformBuffer(uboSize);
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
// set the UBO, always descriptor 0
mDescriptorSet.setBuffer(0, mUbHandle, 0, mUniforms.getSize());
mDescriptorSet.setBuffer(material->getDescriptorSetLayout(),
0, mUbHandle, 0, mUniforms.getSize());
const RasterState& rasterState = material->getRasterState();
// At the moment, only MaterialInstances have a stencil state, but in the future it should be
@@ -142,15 +146,15 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
FEngine::DriverApi& driver = engine.getDriverApi();
FMaterial const* const material = other->getMaterial();
if (!material->getUniformInterfaceBlock().isEmpty()) {
mUniforms.setUniforms(other->getUniformBuffer());
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
}
size_t const uboSize = std::max(size_t(16), material->getUniformInterfaceBlock().getSize());
mUniforms = UniformBuffer(uboSize);
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
// set the UBO, always descriptor 0
mDescriptorSet.setBuffer(0, mUbHandle, 0, mUniforms.getSize());
mDescriptorSet.setBuffer(mMaterial->getDescriptorSetLayout(),
0, mUbHandle, 0, mUniforms.getSize());
if (material->hasDoubleSidedCapability()) {
setDoubleSided(mIsDoubleSided);
@@ -223,7 +227,8 @@ void FMaterialInstance::commit(DriverApi& driver) const {
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
assert_invariant(handle);
mDescriptorSet.setSampler(binding, handle, p.params);
mDescriptorSet.setSampler(mMaterial->getDescriptorSetLayout(),
binding, handle, p.params);
}
}
@@ -239,7 +244,9 @@ void FMaterialInstance::commit(DriverApi& driver) const {
void FMaterialInstance::setParameter(std::string_view const name,
Handle<HwTexture> texture, SamplerParams const params) {
auto const binding = mMaterial->getSamplerBinding(name);
mDescriptorSet.setSampler(binding, texture, params);
mDescriptorSet.setSampler(mMaterial->getDescriptorSetLayout(),
binding, texture, params);
}
void FMaterialInstance::setParameterImpl(std::string_view const name,
@@ -266,6 +273,21 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
#endif
auto const binding = mMaterial->getSamplerBinding(name);
if (texture) {
auto const& descriptorSetLayout = mMaterial->getDescriptorSetLayout();
DescriptorType const descriptorType = descriptorSetLayout.getDescriptorType(binding);
TextureType const textureType = texture->getTextureType();
FILAMENT_CHECK_PRECONDITION(
DescriptorSet::isTextureCompatibleWithDescriptor(textureType, descriptorType))
<< "Texture format " << int(texture->getFormat())
<< " of type " << to_string(textureType)
<< " is not compatible with material \"" << getMaterial()->getName().c_str() << "\""
<< " parameter \"" << name << "\""
<< " of type " << to_string(descriptorType);
}
if (texture && texture->textureHandleCanMutate()) {
mTextureParameters[binding] = { texture, sampler.getSamplerParams() };
} else {
@@ -278,7 +300,8 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
handle = texture->getHwHandleForSampling();
assert_invariant(handle == texture->getHwHandle());
}
mDescriptorSet.setSampler(binding, handle, sampler.getSamplerParams());
mDescriptorSet.setSampler(mMaterial->getDescriptorSetLayout(),
binding, handle, sampler.getSamplerParams());
}
}
@@ -395,29 +418,30 @@ void FMaterialInstance::fixMissingSamplers() const {
auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
return item.binding == binding;
});
FEngine const& engine = mMaterial->getEngine();
// just safety-check, should never fail
if (UTILS_LIKELY(pos != list.end())) {
switch (pos->type) {
case SamplerType::SAMPLER_2D:
mDescriptorSet.setSampler(binding,
engine.getZeroTexture(), {});
break;
case SamplerType::SAMPLER_2D_ARRAY:
mDescriptorSet.setSampler(binding,
engine.getZeroTextureArray(), {});
break;
case SamplerType::SAMPLER_CUBEMAP:
mDescriptorSet.setSampler(binding,
engine.getDummyCubemap()->getHwHandle(), {});
break;
case SamplerType::SAMPLER_EXTERNAL:
case SamplerType::SAMPLER_3D:
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
// we're currently not able to fix-up those
break;
FEngine const& engine = mMaterial->getEngine();
filament::DescriptorSetLayout const& layout = mMaterial->getDescriptorSetLayout();
if (pos->format != SamplerFormat::FLOAT) {
// TODO: we only handle missing samplers that are FLOAT
switch (pos->type) {
case SamplerType::SAMPLER_2D:
mDescriptorSet.setSampler(layout,
binding, engine.getZeroTexture(), {});
break;
case SamplerType::SAMPLER_2D_ARRAY:
mDescriptorSet.setSampler(layout,
binding, engine.getZeroTextureArray(), {});
break;
case SamplerType::SAMPLER_CUBEMAP:
mDescriptorSet.setSampler(layout,
binding, engine.getDummyCubemap()->getHwHandle(), {});
break;
default:
// we're currently not able to fix-up other sampler types
break;
}
}
}
});
+2 -1
View File
@@ -114,7 +114,8 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder)
: mVertexCount(builder->mVertexCount),
mCount(builder->mCount) {
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) {
if (UTILS_UNLIKELY(engine.getSupportedFeatureLevel() <= FeatureLevel::FEATURE_LEVEL_0)) {
// feature level 0 doesn't support morph target buffers
return;
}
+1 -1
View File
@@ -977,7 +977,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// this descriptor-set is also used for ssr/picking/structure and these could be stale
// it would be better to use a separate desriptor-set for those two cases so that we don't
// have to do this
view.unbindSamplers(driver);
view.unbindSamplers(engine);
view.commitUniformsAndSamplers(driver);
});
+9 -2
View File
@@ -64,7 +64,7 @@ using namespace math;
// this is a hack to be able to create a std::function<> with a non-copyable closure
template<class F>
auto make_copyable_function(F&& f) {
static auto make_copyable_function(F&& f) {
using dF = std::decay_t<F>;
auto spf = std::make_shared<dF>(std::forward<F>(f));
return [spf](auto&& ... args) -> decltype(auto) {
@@ -274,7 +274,9 @@ Texture* Texture::Builder::build(Engine& engine) {
// ------------------------------------------------------------------------------------------------
FTexture::FTexture(FEngine& engine, const Builder& builder) {
FTexture::FTexture(FEngine& engine, const Builder& builder)
: mHasBlitSrc(false),
mExternal(false) {
FEngine::DriverApi& driver = engine.getDriverApi();
mDriver = &driver; // this is unfortunately needed for getHwHandleForSampling()
mWidth = static_cast<uint32_t>(builder->mWidth);
@@ -288,6 +290,7 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) {
mTextureIsSwizzled = builder->mTextureIsSwizzled;
mHasBlitSrc = builder->mHasBlitSrc;
mExternal = builder->mExternal;
mTextureType = backend::getTextureType(mFormat);
bool const isImported = builder->mImportedId != 0;
if (mExternal && !isImported) {
@@ -716,6 +719,10 @@ size_t FTexture::getFormatSize(InternalFormat const format) noexcept {
return backend::getFormatSize(format);
}
TextureType FTexture::getTextureType() const noexcept {
return mTextureType;
}
void FTexture::generatePrefilterMipmap(FEngine& engine,
PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets,
+15 -8
View File
@@ -27,6 +27,9 @@
#include <utils/compiler.h>
#include <array>
#include <cmath>
#include <stddef.h>
#include <stdint.h>
@@ -105,18 +108,20 @@ public:
// Size a of a pixel in bytes for the given format
static size_t getFormatSize(InternalFormat format) noexcept;
backend::TextureType getTextureType() const noexcept;
// Returns the with or height for a given mipmap level from the base value.
static inline size_t valueForLevel(uint8_t const level, size_t const baseLevelValue) {
static size_t valueForLevel(uint8_t const level, size_t const baseLevelValue) {
return std::max(size_t(1), baseLevelValue >> level);
}
// Returns the max number of levels for a texture of given max dimensions
static inline uint8_t maxLevelCount(uint32_t const maxDimension) noexcept {
static uint8_t maxLevelCount(uint32_t const maxDimension) noexcept {
return std::max(1, std::ilogbf(float(maxDimension)) + 1);
}
// Returns the max number of levels for a texture of given dimensions
static inline uint8_t maxLevelCount(uint32_t const width, uint32_t const height) noexcept {
static uint8_t maxLevelCount(uint32_t const width, uint32_t const height) noexcept {
uint32_t const maxDimension = std::max(width, height);
return maxLevelCount(maxDimension);
}
@@ -132,7 +137,7 @@ public:
void updateLodRange(uint8_t level) noexcept;
// TODO: remove in a future filament release. See below for description.
inline bool hasBlitSrcUsage() const noexcept {
bool hasBlitSrcUsage() const noexcept {
return mHasBlitSrc;
}
@@ -166,23 +171,25 @@ private:
uint32_t mWidth = 1;
uint32_t mHeight = 1;
uint32_t mDepth = 1;
InternalFormat mFormat = InternalFormat::RGBA8;
Sampler mTarget = Sampler::SAMPLER_2D;
uint8_t mLevelCount = 1;
uint8_t mSampleCount = 1;
std::array<Swizzle, 4> mSwizzle = {
Swizzle::CHANNEL_0, Swizzle::CHANNEL_1,
Swizzle::CHANNEL_2, Swizzle::CHANNEL_3 };
bool mTextureIsSwizzled;
Usage mUsage = Usage::DEFAULT;
backend::TextureType mTextureType;
// TODO: remove in a future filament release.
// Indicates whether the user has set the TextureUsage::BLIT_SRC usage. This will be used to
// temporarily validate whether this texture can be used for readPixels.
bool mHasBlitSrc = false;
bool mExternal = false;
// there is 4 bytes of padding here
bool mHasBlitSrc : 1;
bool mExternal : 1;
bool mTextureIsSwizzled : 1;
FStream* mStream = nullptr; // only needed for streaming textures
};
+105 -44
View File
@@ -68,10 +68,36 @@ FView::FView(FEngine& engine)
mFogEntity(engine.getEntityManager().create()),
mIsStereoSupported(engine.getDriverApi().isStereoSupported()),
mUniforms(engine.getDriverApi()),
mColorPassDescriptorSet(engine, mUniforms) {
mColorPassDescriptorSet{
{ engine, false, mUniforms },
{ engine, true, mUniforms } }
{
DriverApi& driver = engine.getDriverApi();
auto const& layout = engine.getPerRenderableDescriptorSetLayout();
// initialize the common descriptor set with dummy descriptors
mCommonRenderableDescriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::BONES_UNIFORMS,
engine.getDummyUniformBuffer(), 0, sizeof(PerRenderableBoneUib));
mCommonRenderableDescriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::MORPHING_UNIFORMS,
engine.getDummyUniformBuffer(), 0, sizeof(PerRenderableMorphingUib));
mCommonRenderableDescriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
engine.getDummyMorphTargetBuffer()->getPositionsHandle(), {});
mCommonRenderableDescriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
engine.getDummyMorphTargetBuffer()->getTangentsHandle(), {});
mCommonRenderableDescriptorSet.setSampler(layout,
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS,
engine.getZeroTextureArray(), {});
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
debugRegistry.registerProperty("d.view.camera_at_origin",
@@ -125,11 +151,13 @@ FView::FView(FEngine& engine)
mDefaultColorGrading = mColorGrading = engine.getDefaultColorGrading();
mColorPassDescriptorSet.init(
engine,
mLightUbh,
mFroxelizer.getRecordBuffer(),
mFroxelizer.getFroxelBuffer());
for (auto&& colorPassDescriptorSet : mColorPassDescriptorSet) {
colorPassDescriptorSet.init(
engine,
mLightUbh,
mFroxelizer.getRecordBuffer(),
mFroxelizer.getFroxelBuffer());
}
}
FView::~FView() noexcept = default;
@@ -146,7 +174,9 @@ void FView::terminate(FEngine& engine) {
ShadowMapManager::terminate(engine, mShadowMapManager);
mUniforms.terminate(driver);
mColorPassDescriptorSet.terminate(engine.getDescriptorSetLayoutFactory(), driver);
for (auto&& colorPassDescriptorSet : mColorPassDescriptorSet) {
colorPassDescriptorSet.terminate(engine.getDescriptorSetLayoutFactory(), driver);
}
mFroxelizer.terminate(driver);
mCommonRenderableDescriptorSet.terminate(driver);
@@ -429,7 +459,7 @@ void FView::prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexc
*/
const float exposure = Exposure::exposure(cameraInfo.ev100);
mColorPassDescriptorSet.prepareExposure(cameraInfo.ev100);
getColorPassDescriptorSet().prepareExposure(cameraInfo.ev100);
/*
* Indirect light (IBL)
@@ -446,7 +476,7 @@ void FView::prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexc
FSkybox const* const skybox = scene->getSkybox();
intensity = skybox ? skybox->getIntensity() : FIndirectLight::DEFAULT_INTENSITY;
}
mColorPassDescriptorSet.prepareAmbientLight(engine, *ibl, intensity, exposure);
getColorPassDescriptorSet().prepareAmbientLight(engine, *ibl, intensity, exposure);
/*
* Directional light (always at index 0)
@@ -454,7 +484,7 @@ void FView::prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexc
FLightManager::Instance const directionalLight = lightData.elementAt<FScene::LIGHT_INSTANCE>(0);
const float3 sceneSpaceDirection = lightData.elementAt<FScene::DIRECTION>(0); // guaranteed normalized
mColorPassDescriptorSet.prepareDirectionalLight(engine, exposure, sceneSpaceDirection, directionalLight);
getColorPassDescriptorSet().prepareDirectionalLight(engine, exposure, sceneSpaceDirection, directionalLight);
}
CameraInfo FView::computeCameraInfo(FEngine& engine) const noexcept {
@@ -606,7 +636,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
cameraInfo.projection, cameraInfo.zn, cameraInfo.zf)) {
// TODO: might be more consistent to do this in prepareLighting(), but it's not
// strictly necessary
mColorPassDescriptorSet.prepareDynamicLights(mFroxelizer);
getColorPassDescriptorSet().prepareDynamicLights(mFroxelizer);
}
// We need to pass viewMatrix by value here because it extends the scope of this
// function.
@@ -711,6 +741,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
scene->updateUBOs(merged, mRenderableUbh);
mCommonRenderableDescriptorSet.setBuffer(
engine.getPerRenderableDescriptorSetLayout(),
+PerRenderableBindingPoints::OBJECT_UNIFORMS, mRenderableUbh,
0, sizeof(PerRenderableUib));
@@ -734,37 +765,65 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
FRenderableManager& rcm = engine.getRenderableManager();
auto& descriptorSet = rcm.getDescriptorSet(ci);
auto const& layout = engine.getPerRenderableDescriptorSetLayout();
// initialize the descriptor set the first time it's needed
if (UTILS_UNLIKELY(!descriptorSet.getHandle())) {
descriptorSet = DescriptorSet{ engine.getPerRenderableDescriptorSetLayout() };
descriptorSet = DescriptorSet{ layout };
}
descriptorSet.setBuffer(+PerRenderableBindingPoints::OBJECT_UNIFORMS,
descriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::OBJECT_UNIFORMS,
instance.handle ? instance.handle : mRenderableUbh,
0, sizeof(PerRenderableUib));
if (UTILS_UNLIKELY(skinning.handle || morphing.handle)) {
descriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::BONES_UNIFORMS,
engine.getDummyUniformBuffer(), 0, sizeof(PerRenderableBoneUib));
descriptorSet.setBuffer(+PerRenderableBindingPoints::BONES_UNIFORMS,
descriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::MORPHING_UNIFORMS,
engine.getDummyUniformBuffer(), 0, sizeof(PerRenderableMorphingUib));
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
engine.getDummyMorphTargetBuffer()->getPositionsHandle(), {});
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
engine.getDummyMorphTargetBuffer()->getTangentsHandle(), {});
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS,
engine.getZeroTextureArray(), {});
if (UTILS_UNLIKELY(skinning.handle || morphing.handle)) {
descriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::BONES_UNIFORMS,
skinning.handle, 0, sizeof(PerRenderableBoneUib));
descriptorSet.setSampler(+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS,
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS,
skinning.boneIndicesAndWeightHandle, {});
descriptorSet.setBuffer(+PerRenderableBindingPoints::MORPHING_UNIFORMS,
descriptorSet.setBuffer(layout,
+PerRenderableBindingPoints::MORPHING_UNIFORMS,
morphing.handle, 0, sizeof(PerRenderableMorphingUib));
descriptorSet.setSampler(+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
morphing.morphTargetBuffer->getPositionsHandle(), {});
descriptorSet.setSampler(+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
descriptorSet.setSampler(layout,
+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
morphing.morphTargetBuffer->getTangentsHandle(), {});
}
descriptorSet.commit(engine.getPerRenderableDescriptorSetLayout(), driver);
descriptorSet.commit(layout, driver);
// write the descriptor-set handle to the sceneData array for access later
sceneData.elementAt<FScene::DESCRIPTOR_SET_HANDLE>(i) = descriptorSet.getHandle();
sceneData.elementAt<FScene::DESCRIPTOR_SET_HANDLE>(i) =
descriptorSet.getHandle();
} else {
// use the shared descriptor-set
sceneData.elementAt<FScene::DESCRIPTOR_SET_HANDLE>(i) =
@@ -788,12 +847,13 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
auto const& tcm = engine.getTransformManager();
auto const fogTransform = tcm.getWorldTransformAccurate(tcm.getInstance(mFogEntity));
mColorPassDescriptorSet.prepareTime(engine, userTime);
mColorPassDescriptorSet.prepareFog(engine, cameraInfo, fogTransform, mFogOptions,
auto& colorPassDescriptorSet = getColorPassDescriptorSet();
colorPassDescriptorSet.prepareTime(engine, userTime);
colorPassDescriptorSet.prepareFog(engine, cameraInfo, fogTransform, mFogOptions,
scene->getIndirectLight());
mColorPassDescriptorSet.prepareTemporalNoise(engine, mTemporalAntiAliasingOptions);
mColorPassDescriptorSet.prepareBlending(needsAlphaChannel);
mColorPassDescriptorSet.prepareMaterialGlobals(mMaterialGlobals);
colorPassDescriptorSet.prepareTemporalNoise(engine, mTemporalAntiAliasingOptions);
colorPassDescriptorSet.prepareBlending(needsAlphaChannel);
colorPassDescriptorSet.prepareMaterialGlobals(mMaterialGlobals);
}
void FView::computeVisibilityMasks(
@@ -854,12 +914,12 @@ void FView::prepareUpscaler(float2 const scale,
derivativesScale = 0.5f;
}
}
mColorPassDescriptorSet.prepareLodBias(bias, derivativesScale);
getColorPassDescriptorSet().prepareLodBias(bias, derivativesScale);
}
void FView::prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) const noexcept {
SYSTRACE_CALL();
mColorPassDescriptorSet.prepareCamera(engine, cameraInfo);
getColorPassDescriptorSet().prepareCamera(engine, cameraInfo);
}
void FView::prepareViewport(
@@ -868,23 +928,23 @@ void FView::prepareViewport(
SYSTRACE_CALL();
// TODO: we should pass viewport.{left|bottom} to the backend, so it can offset the
// scissor properly.
mColorPassDescriptorSet.prepareViewport(physicalViewport, logicalViewport);
getColorPassDescriptorSet().prepareViewport(physicalViewport, logicalViewport);
}
void FView::prepareSSAO(Handle<HwTexture> ssao) const noexcept {
mColorPassDescriptorSet.prepareSSAO(ssao, mAmbientOcclusionOptions);
getColorPassDescriptorSet().prepareSSAO(ssao, mAmbientOcclusionOptions);
}
void FView::prepareSSR(Handle<HwTexture> ssr,
bool const disableSSR,
float const refractionLodOffset,
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
mColorPassDescriptorSet.prepareSSR(ssr, disableSSR, refractionLodOffset, ssrOptions);
getColorPassDescriptorSet().prepareSSR(ssr, disableSSR, refractionLodOffset, ssrOptions);
}
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
// sampler must be NEAREST
mColorPassDescriptorSet.prepareStructure(structure);
getColorPassDescriptorSet().prepareStructure(structure);
}
void FView::prepareShadow(Handle<HwTexture> texture) const noexcept {
@@ -896,37 +956,38 @@ void FView::prepareShadow(Handle<HwTexture> texture) const noexcept {
}
switch (mShadowType) {
case ShadowType::PCF:
mColorPassDescriptorSet.prepareShadowPCF(texture, uniforms);
getColorPassDescriptorSet().prepareShadowPCF(texture, uniforms);
break;
case ShadowType::VSM:
mColorPassDescriptorSet.prepareShadowVSM(texture, uniforms, mVsmShadowOptions);
getColorPassDescriptorSet().prepareShadowVSM(texture, uniforms, mVsmShadowOptions);
break;
case ShadowType::DPCF:
mColorPassDescriptorSet.prepareShadowDPCF(texture, uniforms, mSoftShadowOptions);
getColorPassDescriptorSet().prepareShadowDPCF(texture, uniforms, mSoftShadowOptions);
break;
case ShadowType::PCSS:
mColorPassDescriptorSet.prepareShadowPCSS(texture, uniforms, mSoftShadowOptions);
getColorPassDescriptorSet().prepareShadowPCSS(texture, uniforms, mSoftShadowOptions);
break;
case ShadowType::PCFd:
mColorPassDescriptorSet.prepareShadowPCFDebug(texture, uniforms);
getColorPassDescriptorSet().prepareShadowPCFDebug(texture, uniforms);
break;
}
}
void FView::prepareShadowMapping(bool const highPrecision) const noexcept {
void FView::prepareShadowMapping(FEngine const& engine, bool const highPrecision) const noexcept {
BufferObjectHandle ubo{ engine.getDummyUniformBuffer() };
if (mHasShadowing) {
assert_invariant(mShadowMapManager);
mColorPassDescriptorSet.prepareShadowMapping(
mShadowMapManager->getShadowUniformsHandle(), highPrecision);
ubo = mShadowMapManager->getShadowUniformsHandle();
}
getColorPassDescriptorSet().prepareShadowMapping(ubo, highPrecision);
}
void FView::commitUniformsAndSamplers(DriverApi& driver) const noexcept {
mColorPassDescriptorSet.commit(driver);
getColorPassDescriptorSet().commit(driver);
}
void FView::unbindSamplers(DriverApi& driver) noexcept {
mColorPassDescriptorSet.unbindSamplers(driver);
void FView::unbindSamplers(FEngine& engine) noexcept {
getColorPassDescriptorSet().unbindSamplers(engine);
}
void FView::commitFroxels(DriverApi& driverApi) const noexcept {
+6 -4
View File
@@ -178,11 +178,11 @@ public:
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadowMapping(bool highPrecision) const noexcept;
void prepareShadowMapping(FEngine const& engine, bool highPrecision) const noexcept;
void commitFroxels(backend::DriverApi& driverApi) const noexcept;
void commitUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
void unbindSamplers(backend::DriverApi& driver) noexcept;
void unbindSamplers(FEngine& engine) noexcept;
utils::JobSystem::Job* getFroxelizerSync() const noexcept { return mFroxelizerSync; }
void setFroxelizerSync(utils::JobSystem::Job* sync) noexcept { mFroxelizerSync = sync; }
@@ -440,7 +440,9 @@ public:
static void cullRenderables(utils::JobSystem& js, FScene::RenderableSoa& renderableData,
Frustum const& frustum, size_t bit) noexcept;
ColorPassDescriptorSet& getColorPassDescriptorSet() noexcept { return mColorPassDescriptorSet; }
ColorPassDescriptorSet& getColorPassDescriptorSet() const noexcept {
return mColorPassDescriptorSet[mShadowType == ShadowType::PCF ? 0 : 1];
}
// Returns the frame history FIFO. This is typically used by the FrameGraph to access
// previous frame data.
@@ -587,7 +589,7 @@ private:
RenderQuality mRenderQuality;
mutable TypedUniformBuffer<PerViewUib> mUniforms;
mutable ColorPassDescriptorSet mColorPassDescriptorSet;
mutable ColorPassDescriptorSet mColorPassDescriptorSet[2];
mutable FrameHistory mFrameHistory{};
+34 -31
View File
@@ -79,7 +79,7 @@ uint8_t ColorPassDescriptorSet::getIndex(
index |= 0x2;
}
if (!fog) {
if (fog) {
// this will remove samplers needed for fog
index |= 0x4;
}
@@ -88,27 +88,18 @@ uint8_t ColorPassDescriptorSet::getIndex(
return index;
}
ColorPassDescriptorSet::ColorPassDescriptorSet(FEngine& engine,
ColorPassDescriptorSet::ColorPassDescriptorSet(FEngine& engine, bool const vsm,
TypedUniformBuffer<PerViewUib>& uniforms) noexcept
: mUniforms(uniforms) {
constexpr UserVariantFilterMask filterFog = UserVariantFilterMask(UserVariantFilterBit::FOG);
constexpr UserVariantFilterMask keepFog = UserVariantFilterMask(0);
: mUniforms(uniforms), mIsVsm(vsm) {
for (bool const lit: { false, true }) {
for (bool const ssr: { false, true }) {
for (bool const fog: { false, true }) {
auto index = getIndex(lit, ssr, fog);
auto const index = getIndex(lit, ssr, fog);
mDescriptorSetLayout[index] = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(),
descriptor_sets::getPerViewDescriptorSetLayout(
MaterialDomain::SURFACE,
fog ? keepFog : filterFog,
lit,
ssr ? ReflectionMode::SCREEN_SPACE : ReflectionMode::DEFAULT,
ssr ? RefractionMode::SCREEN_SPACE : RefractionMode::NONE)
MaterialDomain::SURFACE, lit, ssr, fog, vsm)
};
mDescriptorSet[index] = DescriptorSet{ mDescriptorSetLayout[index] };
}
@@ -118,11 +109,11 @@ ColorPassDescriptorSet::ColorPassDescriptorSet(FEngine& engine,
setBuffer(+PerViewBindingPoints::FRAME_UNIFORMS,
uniforms.getUboHandle(), 0, uniforms.getSize());
if (engine.getDFG().isValid()) {
TextureSampler const sampler(TextureSampler::MagFilter::LINEAR);
setSampler(+PerViewBindingPoints::IBL_DFG_LUT,
engine.getDFG().getTexture(), sampler.getSamplerParams());
}
setSampler(+PerViewBindingPoints::IBL_DFG_LUT,
engine.getDFG().isValid() ?
engine.getDFG().getTexture() : engine.getZeroTexture(), {
.filterMag = SamplerMagFilter::LINEAR
});
}
void ColorPassDescriptorSet::init(
@@ -130,12 +121,14 @@ void ColorPassDescriptorSet::init(
BufferObjectHandle lights,
BufferObjectHandle recordBuffer,
BufferObjectHandle froxelBuffer) noexcept {
for (auto&& descriptorSet: mDescriptorSet) {
descriptorSet.setBuffer(+PerViewBindingPoints::LIGHTS,
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
auto& descriptorSet = mDescriptorSet[i];
auto const& layout = mDescriptorSetLayout[i];
descriptorSet.setBuffer(layout, +PerViewBindingPoints::LIGHTS,
lights, 0, CONFIG_MAX_LIGHT_COUNT * sizeof(LightsUib));
descriptorSet.setBuffer(+PerViewBindingPoints::RECORD_BUFFER,
descriptorSet.setBuffer(layout, +PerViewBindingPoints::RECORD_BUFFER,
recordBuffer, 0, sizeof(FroxelRecordUib));
descriptorSet.setBuffer(+PerViewBindingPoints::FROXEL_BUFFER,
descriptorSet.setBuffer(layout, +PerViewBindingPoints::FROXEL_BUFFER,
froxelBuffer, 0, Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()));
}
}
@@ -305,6 +298,7 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
AmbientOcclusionOptions const& options) noexcept {
// High quality sampling is enabled only if AO itself is enabled and upsampling quality is at
// least set to high and of course only if upsampling is needed.
const bool highQualitySampling = options.upsampling >= QualityLevel::HIGH
@@ -537,20 +531,28 @@ void ColorPassDescriptorSet::commit(DriverApi& driver) noexcept {
driver.updateBufferObject(mUniforms.getUboHandle(),
mUniforms.toBufferDescriptor(driver), 0);
}
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
mDescriptorSet[i].commit(mDescriptorSetLayout[i], driver);
}
}
void ColorPassDescriptorSet::unbindSamplers(DriverApi&) noexcept {
void ColorPassDescriptorSet::unbindSamplers(FEngine& engine) noexcept {
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
// this descriptor-set is also used for ssr/picking/structure and these could be stale
// it would be better to use a separate descriptor-set for those two cases so that we don't
// have to do this
setSampler(+PerViewBindingPoints::STRUCTURE, {}, {});
setSampler(+PerViewBindingPoints::SHADOW_MAP, {}, {});
setSampler(+PerViewBindingPoints::SSAO, {}, {});
setSampler(+PerViewBindingPoints::SSR, {}, {});
setBuffer(+PerViewBindingPoints::SHADOWS,
engine.getDummyUniformBuffer(), 0, sizeof(ShadowUib));
setSampler(+PerViewBindingPoints::STRUCTURE,
engine.getZeroTexture(), {});
setSampler(+PerViewBindingPoints::SHADOW_MAP,
engine.getOneTextureArrayDepth(), {});
setSampler(+PerViewBindingPoints::SSAO,
engine.getZeroTextureArray(), {});
setSampler(+PerViewBindingPoints::SSR,
engine.getZeroTextureArray(), {});
}
void ColorPassDescriptorSet::setSampler(descriptor_binding_t const binding,
@@ -558,7 +560,7 @@ void ColorPassDescriptorSet::setSampler(descriptor_binding_t const binding,
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
auto samplers = mDescriptorSetLayout[i].getSamplerDescriptors();
if (samplers[binding]) {
mDescriptorSet[i].setSampler(binding, th, params);
mDescriptorSet[i].setSampler(mDescriptorSetLayout[i], binding, th, params);
}
}
}
@@ -566,9 +568,10 @@ void ColorPassDescriptorSet::setSampler(descriptor_binding_t const binding,
void ColorPassDescriptorSet::setBuffer(descriptor_binding_t const binding,
BufferObjectHandle boh, uint32_t const offset, uint32_t const size) noexcept {
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
auto ubos = mDescriptorSetLayout[i].getUniformBufferDescriptors();
auto const& layout = mDescriptorSetLayout[i];
auto ubos = layout.getUniformBufferDescriptors();
if (ubos[binding]) {
mDescriptorSet[i].setBuffer(binding, boh, offset, size);
mDescriptorSet[i].setBuffer(layout, binding, boh, offset, size);
}
}
}
+12 -8
View File
@@ -66,16 +66,16 @@ class ColorPassDescriptorSet {
using LightManagerInstance = utils::EntityInstance<LightManager>;
using TextureHandle = backend::Handle<backend::HwTexture>;
static constexpr uint32_t const SHADOW_SAMPLING_RUNTIME_PCF = 0u;
static constexpr uint32_t const SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
static constexpr uint32_t const SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
static constexpr uint32_t const SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCF = 0u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
public:
static uint8_t getIndex(bool lit, bool ssr, bool fog) noexcept;
ColorPassDescriptorSet(FEngine& engine,
ColorPassDescriptorSet(FEngine& engine, bool vsm,
TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
void init(
@@ -153,13 +153,15 @@ public:
// update local data into GPU UBO
void commit(backend::DriverApi& driver) noexcept;
void unbindSamplers(backend::DriverApi& driver) noexcept;
void unbindSamplers(FEngine& engine) noexcept;
// bind this UBO
void bind(backend::DriverApi& driver, uint8_t const index) const noexcept {
mDescriptorSet[index].bind(driver, DescriptorSetBindingPoints::PER_VIEW);
}
bool isVSM() const noexcept { return mIsVsm; }
private:
static constexpr size_t DESCRIPTOR_LAYOUT_COUNT = 8;
@@ -169,11 +171,13 @@ private:
void setBuffer(backend::descriptor_binding_t binding,
backend::BufferObjectHandle boh, uint32_t offset, uint32_t size) noexcept;
static void prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
TypedUniformBuffer<PerViewUib>& mUniforms;
std::array<DescriptorSetLayout, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSetLayout;
std::array<DescriptorSet, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSet;
static void prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
bool const mIsVsm;
};
} // namespace filament
+85 -9
View File
@@ -28,6 +28,7 @@
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utility>
#include <limits>
@@ -86,6 +87,7 @@ void DescriptorSet::commitSlow(DescriptorSetLayout const& layout,
mValid.forEachSetBit([&layout, &driver,
dsh = mDescriptorSetHandle, descriptors = mDescriptors.data()]
(backend::descriptor_binding_t const binding) {
assert_invariant(layout.isValid(binding));
if (layout.isSampler(binding)) {
driver.updateDescriptorSetTexture(dsh, binding,
descriptors[binding].texture.th,
@@ -113,7 +115,7 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
// within the renderpass. We have to comment the assert out since it crashed a client's debug
// build.
// assert_invariant(mDirty.none());
if (mDirty.any() && !mSetAfterCommitWarning) {
if (UTILS_VERY_UNLIKELY(mDirty.any() && !mSetAfterCommitWarning)) {
mDirty.forEachSetBit([&](uint8_t const binding) {
utils::slog.w << "Descriptor set (handle=" << mDescriptorSetHandle.getId()
<< ") binding=" << (int) binding
@@ -124,35 +126,109 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
driver.bindDescriptorSet(mDescriptorSetHandle, +set, std::move(dynamicOffsets));
}
void DescriptorSet::setBuffer(
void DescriptorSet::setBuffer(DescriptorSetLayout const& layout,
backend::descriptor_binding_t const binding,
backend::Handle<backend::HwBufferObject> boh, uint32_t const offset, uint32_t const size) noexcept {
// TODO: validate it's the right kind of descriptor
backend::Handle<backend::HwBufferObject> boh, uint32_t const offset, uint32_t const size) {
// Validate it's the right kind of descriptor
using DSLB = backend::DescriptorSetLayoutBinding;
FILAMENT_CHECK_PRECONDITION(DSLB::isBuffer(layout.getDescriptorType(binding)))
<< "descriptor " << +binding << "is not a buffer";
if (mDescriptors[binding].buffer.boh != boh || mDescriptors[binding].buffer.size != size) {
// we don't set the dirty bit if only offset changes
mDirty.set(binding);
}
mDescriptors[binding].buffer = { boh, offset, size };
mValid.set(binding, (bool)boh);
mValid.set(binding, bool(boh));
}
void DescriptorSet::setSampler(
DescriptorSetLayout const& layout,
backend::descriptor_binding_t const binding,
backend::Handle<backend::HwTexture> th, backend::SamplerParams const params) noexcept {
// TODO: validate it's the right kind of descriptor
backend::Handle<backend::HwTexture> th, backend::SamplerParams const params) {
using namespace backend;
using DSLB = DescriptorSetLayoutBinding;
// Validate it's the right kind of descriptor
auto type = layout.getDescriptorType(binding);
FILAMENT_CHECK_PRECONDITION(DSLB::isSampler(type))
<< "descriptor " << +binding << " is not a sampler";
FILAMENT_CHECK_PRECONDITION(
!(params.compareMode == SamplerCompareMode::COMPARE_TO_TEXTURE && !isDepthDescriptor(type)))
<< "descriptor " << +binding
<< " is not of type DEPTH, but sampler is in COMPARE_TO_TEXTURE mode";
FILAMENT_CHECK_PRECONDITION(
!(params.isFiltered() &&
isDepthDescriptor(type) &&
params.compareMode != SamplerCompareMode::COMPARE_TO_TEXTURE))
<< "descriptor " << +binding
<< " is of type filtered DEPTH, but sampler not in COMPARE_TO_TEXTURE mode";
if (mDescriptors[binding].texture.th != th || mDescriptors[binding].texture.params != params) {
mDirty.set(binding);
}
mDescriptors[binding].texture = { th, params };
mValid.set(binding, (bool)th);
mValid.set(binding, bool(th));
}
DescriptorSet DescriptorSet::duplicate(DescriptorSetLayout const& layout) const noexcept {
DescriptorSet set{layout};
set.mDescriptors = mDescriptors; // Use the vector's assignment operator
set.mDirty = mDirty;
set.mDirty = mValid | mDirty; // Dirty all valid descriptors so they're updated during commit
set.mValid = mValid;
return set;
}
bool DescriptorSet::isTextureCompatibleWithDescriptor(
backend::TextureType t, backend::DescriptorType d) noexcept {
using namespace backend;
switch (d) {
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_3D_FLOAT:
// DEPTH_STENCIL is treated as accessing the depth component. OpenGL 4.3
// allows to specify which one, but not filament.
// Depth textures can be used as an unfiltered float sampler
return t == TextureType::FLOAT || t == TextureType::DEPTH || t == TextureType::DEPTH_STENCIL;
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_3D_INT:
return t == TextureType::INT;
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_3D_UINT:
return t == TextureType::UINT;
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
// DEPTH_STENCIL is treated as accessing the depth component. OpenGL 4.3
// allows to specify which one, but not filament.
return t == TextureType::DEPTH || t == TextureType::DEPTH_STENCIL;
case DescriptorType::SAMPLER_EXTERNAL:
case DescriptorType::UNIFORM_BUFFER:
case DescriptorType::SHADER_STORAGE_BUFFER:
case DescriptorType::INPUT_ATTACHMENT:
return false;
}
// should never happen
return false;
}
} // namespace filament
+9 -4
View File
@@ -62,14 +62,16 @@ public:
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept;
// sets a ubo/ssbo descriptor
void setBuffer(backend::descriptor_binding_t binding,
void setBuffer(DescriptorSetLayout const& layout,
backend::descriptor_binding_t binding,
backend::Handle<backend::HwBufferObject> boh,
uint32_t offset, uint32_t size) noexcept;
uint32_t offset, uint32_t size);
// sets a sampler descriptor
void setSampler(backend::descriptor_binding_t binding,
void setSampler(DescriptorSetLayout const& layout,
backend::descriptor_binding_t binding,
backend::Handle<backend::HwTexture> th,
backend::SamplerParams params) noexcept;
backend::SamplerParams params);
// Used for duplicating material
DescriptorSet duplicate(DescriptorSetLayout const& layout) const noexcept;
@@ -82,6 +84,9 @@ public:
return mValid;
}
static bool isTextureCompatibleWithDescriptor(
backend::TextureType t, backend::DescriptorType d) noexcept;
private:
struct Desc {
Desc() noexcept { }
+12 -5
View File
@@ -20,6 +20,9 @@
#include "details/Engine.h"
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <backend/DriverEnums.h>
#include <algorithm>
@@ -35,11 +38,15 @@ DescriptorSetLayout::DescriptorSetLayout(
backend::DescriptorSetLayout descriptorSetLayout) noexcept {
for (auto&& desc : descriptorSetLayout.bindings) {
mMaxDescriptorBinding = std::max(mMaxDescriptorBinding, desc.binding);
mSamplers.set(desc.binding,
desc.type == backend::DescriptorType::SAMPLER ||
desc.type == backend::DescriptorType::SAMPLER_EXTERNAL);
mUniformBuffers.set(desc.binding,
desc.type == backend::DescriptorType::UNIFORM_BUFFER);
mSamplers.set(desc.binding, backend::DescriptorSetLayoutBinding::isSampler(desc.type));
mUniformBuffers.set(desc.binding, desc.type == backend::DescriptorType::UNIFORM_BUFFER);
}
assert_invariant(mMaxDescriptorBinding < utils::bitset64::BIT_COUNT);
mDescriptorTypes = utils::FixedCapacityVector<backend::DescriptorType>(mMaxDescriptorBinding + 1);
for (auto&& desc : descriptorSetLayout.bindings) {
mDescriptorTypes[desc.binding] = desc.type;
}
mDescriptorSetLayoutHandle = factory.create(driver,
+11
View File
@@ -23,6 +23,7 @@
#include <backend/Handle.h>
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <stddef.h>
#include <stdint.h>
@@ -56,6 +57,10 @@ public:
return mMaxDescriptorBinding;
}
bool isValid(backend::descriptor_binding_t const binding) const noexcept {
return mSamplers[binding] || mUniformBuffers[binding];
}
bool isSampler(backend::descriptor_binding_t const binding) const noexcept {
return mSamplers[binding];
}
@@ -68,11 +73,17 @@ public:
return mUniformBuffers;
}
backend::DescriptorType getDescriptorType(
backend::descriptor_binding_t const binding) const noexcept {
return mDescriptorTypes[binding];
}
private:
backend::DescriptorSetLayoutHandle mDescriptorSetLayoutHandle;
utils::bitset64 mSamplers;
utils::bitset64 mUniformBuffers;
uint8_t mMaxDescriptorBinding = 0;
utils::FixedCapacityVector<backend::DescriptorType> mDescriptorTypes;
};
+2 -1
View File
@@ -53,7 +53,8 @@ void PostProcessDescriptorSet::terminate(HwDescriptorSetLayoutFactory& factory,
void PostProcessDescriptorSet::setFrameUniforms(DriverApi& driver,
TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
// initialize the descriptor-set
mDescriptorSet.setBuffer(+PerViewBindingPoints::FRAME_UNIFORMS,
mDescriptorSet.setBuffer(mDescriptorSetLayout,
+PerViewBindingPoints::FRAME_UNIFORMS,
uniforms.getUboHandle(), 0, uniforms.getSize());
mDescriptorSet.commit(mDescriptorSetLayout, driver);
+2 -2
View File
@@ -46,8 +46,8 @@ ShadowMapDescriptorSet::ShadowMapDescriptorSet(FEngine& engine) noexcept {
mDescriptorSet = DescriptorSet{ engine.getPerViewDescriptorSetLayoutDepthVariant() };
// initialize the descriptor-set
mDescriptorSet.setBuffer(+PerViewBindingPoints::FRAME_UNIFORMS,
mUniformBufferHandle, 0, sizeof(PerViewUib));
mDescriptorSet.setBuffer(engine.getPerViewDescriptorSetLayoutDepthVariant(),
+PerViewBindingPoints::FRAME_UNIFORMS, mUniformBufferHandle, 0, sizeof(PerViewUib));
}
void ShadowMapDescriptorSet::terminate(DriverApi& driver) {
+16 -10
View File
@@ -53,28 +53,32 @@ void SsrPassDescriptorSet::terminate(DriverApi& driver) {
driver.destroyBufferObject(mShadowUbh);
}
void SsrPassDescriptorSet::setFrameUniforms(TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
void SsrPassDescriptorSet::setFrameUniforms(FEngine const& engine,
TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
// initialize the descriptor-set
mDescriptorSet.setBuffer(+PerViewBindingPoints::FRAME_UNIFORMS,
mDescriptorSet.setBuffer(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::FRAME_UNIFORMS,
uniforms.getUboHandle(), 0, uniforms.getSize());
// This is actually not used for the SSR variants, but the descriptor-set layout needs
// to have this UBO because the fragment shader used is the "generic" one. Both Metal
// and GL would be okay without this, but Vulkan's validation layer would complain.
mDescriptorSet.setBuffer(+PerViewBindingPoints::SHADOWS, mShadowUbh, 0, sizeof(ShadowUib));
mDescriptorSet.setBuffer(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::SHADOWS, mShadowUbh, 0, sizeof(ShadowUib));
mUniforms = std::addressof(uniforms);
}
void SsrPassDescriptorSet::prepareHistorySSR(Handle<HwTexture> ssr,
void SsrPassDescriptorSet::prepareHistorySSR(FEngine const& engine, Handle<HwTexture> ssr,
mat4f const& historyProjection,
mat4f const& uvFromViewMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
mDescriptorSet.setSampler(+PerViewBindingPoints::SSR, ssr, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
mDescriptorSet.setSampler(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::SSR, ssr, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
assert_invariant(mUniforms);
auto& s = mUniforms->edit();
@@ -86,9 +90,11 @@ void SsrPassDescriptorSet::prepareHistorySSR(Handle<HwTexture> ssr,
s.ssrStride = ssrOptions.stride;
}
void SsrPassDescriptorSet::prepareStructure(Handle<HwTexture> structure) noexcept {
void SsrPassDescriptorSet::prepareStructure(FEngine const& engine,
Handle<HwTexture> structure) noexcept {
// sampler must be NEAREST
mDescriptorSet.setSampler(+PerViewBindingPoints::STRUCTURE, structure, {});
mDescriptorSet.setSampler(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::STRUCTURE, structure, {});
}
void SsrPassDescriptorSet::commit(FEngine& engine) noexcept {
+3 -3
View File
@@ -47,11 +47,11 @@ public:
void terminate(backend::DriverApi& driver);
void setFrameUniforms(TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
void setFrameUniforms(FEngine const& engine, TypedUniformBuffer<PerViewUib>& uniforms) noexcept;
void prepareStructure(TextureHandle structure) noexcept;
void prepareStructure(FEngine const& engine, TextureHandle structure) noexcept;
void prepareHistorySSR(TextureHandle ssr,
void prepareHistorySSR(FEngine const& engine, TextureHandle ssr,
math::mat4f const& historyProjection,
math::mat4f const& uvFromViewMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.60.0"
spec.version = "1.59.5"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.60.0/filament-v1.60.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.5/filament-v1.59.5-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
+2 -1
View File
@@ -102,7 +102,8 @@ project in Xcode to see changes take effect.
## Building iOS Samples with ASan / UBSan
1. Turn on ASan / UBSan in Filament's top-level CMakeLists.txt by uncommenting the following line:
1. Turn on ASan / UBSan in Filament's top-level CMakeLists.txt by passing
`-DFILAMENT_ENABLE_ASAN_UBSAN=1` to trigger the following line:
```
set(EXTRA_SANITIZE_OPTIONS "-fsanitize=undefined -fsanitize=address")
@@ -35,23 +35,20 @@ backend::DescriptorSetLayout const& getPerRenderableLayout() noexcept;
backend::DescriptorSetLayout getPerViewDescriptorSetLayout(
MaterialDomain domain,
UserVariantFilterMask variantFilter,
bool isLit,
ReflectionMode reflectionMode,
RefractionMode refractionMode) noexcept;
bool isLit, bool isSSR, bool hasFog,
bool isVSM) noexcept;
backend::DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
Variant variant,
MaterialDomain domain,
UserVariantFilterMask variantFilter,
bool isLit,
ReflectionMode reflectionMode,
RefractionMode refractionMode) noexcept;
bool isLit, bool isSSR, bool hasFog) noexcept;
utils::CString getDescriptorName(
DescriptorSetBindingPoints set,
backend::descriptor_binding_t binding) noexcept;
backend::DescriptorType getDescriptorType(backend::SamplerType type, backend::SamplerFormat format);
} // namespace filament::descriptor_sets
+107 -34
View File
@@ -24,21 +24,28 @@
#include <backend/DriverEnums.h>
#include <utils/CString.h>
#include <utils/Panic.h>
#include <utils/StaticString.h>
#include <utils/debug.h>
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <utility>
namespace filament::descriptor_sets {
using namespace backend;
// used for post-processing passes
static constexpr std::initializer_list<DescriptorSetLayoutBinding> postProcessDescriptorSetLayoutList = {
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
};
// used to generate shadow-maps
static constexpr std::initializer_list<DescriptorSetLayoutBinding> depthVariantDescriptorSetLayoutList = {
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
};
@@ -51,32 +58,88 @@ static constexpr std::initializer_list<DescriptorSetLayoutBinding> depthVariantD
static constexpr std::initializer_list<DescriptorSetLayoutBinding> ssrVariantDescriptorSetLayoutList = {
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
{ DescriptorType::SAMPLER_2D_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
{ DescriptorType::SAMPLER_2D_ARRAY_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
};
// Used for generating the color pass (i.e. the main pass). This is in fact a template that gets
// declined into 8 different layouts, based on variants.
//
// Note about the SHADOW_MAP binding points:
// This descriptor can either be a SAMPLER_FLOAT or a SAMPLER_DEPTH,
// and there are 3 cases to consider:
//
// | TextureType | CompareMode | Filtered | SamplerType | Variant |
// ---------+-------------+-------------+----------+-------------+---------+
// PCF | DEPTH | COMPARE | Yes | DEPTH | - |
// VSM | FLOAT | NONE | Yes | FLOAT | VSM |
// OTHER | DEPTH | NONE | No | FLOAT | VSM |
//
// The SamplerType to use depends on the Variant. Variant::VSM is set for all cases except PCM.
//
static constexpr std::initializer_list<DescriptorSetLayoutBinding> perViewDescriptorSetLayoutList = {
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::LIGHTS },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::RECORD_BUFFER },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FROXEL_BUFFER },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOW_MAP },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_DFG_LUT },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_SPECULAR },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSAO },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
{ DescriptorType::SAMPLER_2D_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
{ DescriptorType::SAMPLER_2D_ARRAY_DEPTH, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOW_MAP },
{ DescriptorType::SAMPLER_2D_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_DFG_LUT },
{ DescriptorType::SAMPLER_CUBE_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::IBL_SPECULAR },
{ DescriptorType::SAMPLER_2D_ARRAY_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSAO },
{ DescriptorType::SAMPLER_2D_ARRAY_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
{ DescriptorType::SAMPLER_CUBE_FLOAT, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
};
static constexpr std::initializer_list<DescriptorSetLayoutBinding> perRenderableDescriptorSetLayoutList = {
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS },
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_POSITIONS },
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_TANGENTS },
{ DescriptorType::SAMPLER, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS },
{ DescriptorType::SAMPLER_2D_ARRAY_FLOAT, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_POSITIONS },
{ DescriptorType::SAMPLER_2D_ARRAY_INT, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::MORPH_TARGET_TANGENTS },
{ DescriptorType::SAMPLER_2D_ARRAY_FLOAT, ShaderStageFlags::VERTEX , +PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS },
};
struct PairSamplerTypeFormatHasher {
std::size_t operator()(const std::pair<SamplerType, SamplerFormat>& p) const {
using UnderlyingSamplerType = std::underlying_type_t<SamplerType>;
using UnderlyingSamplerFormat = std::underlying_type_t<SamplerFormat>;
std::size_t seed = 0;
std::size_t const hash1 = std::hash<UnderlyingSamplerType>{}(
static_cast<UnderlyingSamplerType>(p.first)
);
std::size_t const hash2 = std::hash<UnderlyingSamplerFormat>{}(
static_cast<UnderlyingSamplerFormat>(p.second)
);
seed ^= hash1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= hash2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
static const std::unordered_map<
std::pair<SamplerType, SamplerFormat>, DescriptorType, PairSamplerTypeFormatHasher> sDescriptorTypeMap{
{{ SamplerType::SAMPLER_2D, SamplerFormat::INT }, DescriptorType::SAMPLER_2D_INT },
{{ SamplerType::SAMPLER_2D, SamplerFormat::UINT }, DescriptorType::SAMPLER_2D_UINT },
{{ SamplerType::SAMPLER_2D, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_2D_FLOAT },
{{ SamplerType::SAMPLER_2D, SamplerFormat::SHADOW }, DescriptorType::SAMPLER_2D_DEPTH },
{{ SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::INT }, DescriptorType::SAMPLER_2D_ARRAY_INT },
{{ SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::UINT }, DescriptorType::SAMPLER_2D_ARRAY_UINT },
{{ SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_2D_ARRAY_FLOAT },
{{ SamplerType::SAMPLER_2D_ARRAY, SamplerFormat::SHADOW }, DescriptorType::SAMPLER_2D_ARRAY_DEPTH },
{{ SamplerType::SAMPLER_CUBEMAP, SamplerFormat::INT }, DescriptorType::SAMPLER_CUBE_INT },
{{ SamplerType::SAMPLER_CUBEMAP, SamplerFormat::UINT }, DescriptorType::SAMPLER_CUBE_UINT },
{{ SamplerType::SAMPLER_CUBEMAP, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_CUBE_FLOAT },
{{ SamplerType::SAMPLER_CUBEMAP, SamplerFormat::SHADOW }, DescriptorType::SAMPLER_CUBE_DEPTH },
{{ SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::INT }, DescriptorType::SAMPLER_CUBE_ARRAY_INT },
{{ SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::UINT }, DescriptorType::SAMPLER_CUBE_ARRAY_UINT },
{{ SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT },
{{ SamplerType::SAMPLER_CUBEMAP_ARRAY, SamplerFormat::SHADOW }, DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH },
{{ SamplerType::SAMPLER_3D, SamplerFormat::INT }, DescriptorType::SAMPLER_3D_INT },
{{ SamplerType::SAMPLER_3D, SamplerFormat::UINT }, DescriptorType::SAMPLER_3D_UINT },
{{ SamplerType::SAMPLER_3D, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_3D_FLOAT },
{{ SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_EXTERNAL }
};
// used for post-processing passes
@@ -146,12 +209,12 @@ utils::CString getDescriptorName(DescriptorSetBindingPoints const set,
switch (set) {
case DescriptorSetBindingPoints::PER_VIEW: {
auto pos = set0.find(binding);
auto const pos = set0.find(binding);
assert_invariant(pos != set0.end());
return { pos->second.data(), pos->second.size() };
}
case DescriptorSetBindingPoints::PER_RENDERABLE: {
auto pos = set1.find(binding);
auto const pos = set1.find(binding);
assert_invariant(pos != set1.end());
return { pos->second.data(), pos->second.size() };
}
@@ -160,17 +223,13 @@ utils::CString getDescriptorName(DescriptorSetBindingPoints const set,
return "MaterialParams";
}
}
return "Unknown";
}
DescriptorSetLayout getPerViewDescriptorSetLayout(
MaterialDomain const domain,
UserVariantFilterMask const variantFilter,
bool const isLit,
ReflectionMode const reflectionMode,
RefractionMode const refractionMode) noexcept {
bool const ssr = reflectionMode == ReflectionMode::SCREEN_SPACE ||
refractionMode == RefractionMode::SCREEN_SPACE;
bool const isLit, bool const isSSR, bool const hasFog,
bool const isVSM) noexcept {
switch (domain) {
case MaterialDomain::SURFACE: {
@@ -189,7 +248,7 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
layout.bindings.end());
}
// remove descriptors not needed for SSRs
if (!ssr) {
if (!isSSR) {
layout.bindings.erase(
std::remove_if(layout.bindings.begin(), layout.bindings.end(),
[](auto const& entry) {
@@ -199,7 +258,7 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
}
// remove fog descriptor if filtered out
if (variantFilter & (UserVariantFilterMask)UserVariantFilterBit::FOG) {
if (!hasFog) {
layout.bindings.erase(
std::remove_if(layout.bindings.begin(), layout.bindings.end(),
[](auto const& entry) {
@@ -207,6 +266,17 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
}),
layout.bindings.end());
}
// change the SHADOW_MAP descriptor type for VSM
if (isVSM) {
auto const pos = std::find_if(layout.bindings.begin(), layout.bindings.end(),
[](auto const& v) {
return v.binding == PerViewBindingPoints::SHADOW_MAP;
});
if (pos != layout.bindings.end()) {
pos->type = DescriptorType::SAMPLER_2D_ARRAY_FLOAT;
}
}
return layout;
}
case MaterialDomain::POST_PROCESS:
@@ -219,11 +289,8 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
Variant const variant,
MaterialDomain domain,
UserVariantFilterMask const variantFilter,
bool const isLit,
ReflectionMode const reflectionMode,
RefractionMode const refractionMode) noexcept {
MaterialDomain const domain,
bool const isLit, bool const isSSR, bool const hasFog) noexcept {
if (Variant::isValidDepthVariant(variant)) {
return depthVariantDescriptorSetLayout;
}
@@ -231,11 +298,17 @@ DescriptorSetLayout getPerViewDescriptorSetLayoutWithVariant(
return ssrVariantDescriptorSetLayout;
}
// We need to filter out all the descriptors not included in the "resolved" layout below
return getPerViewDescriptorSetLayout(domain, variantFilter,
isLit, reflectionMode, refractionMode);
return getPerViewDescriptorSetLayout(domain, isLit, isSSR, hasFog,
Variant::isVSMVariant(variant));
}
DescriptorType getDescriptorType(SamplerType const type, SamplerFormat const format) {
auto const pos = sDescriptorTypeMap.find({ type, format });
FILAMENT_CHECK_PRECONDITION(pos != sDescriptorTypeMap.end())
<< "Incompatible Sampler Format " << to_string(format)
<< " and Type " << to_string(type);
return pos->second;
}
template<class ITERATOR, class PREDICATE>
constexpr static ITERATOR find_if(ITERATOR first, ITERATOR last, PREDICATE pred) {
+1 -3
View File
@@ -56,7 +56,6 @@ set(PRIVATE_HDRS
src/MetalArgumentBuffer.h
src/ShaderMinifier.h
src/SpirvFixup.h
src/SpirvRemapWrapper.h
src/sca/ASTHelpers.h
src/sca/GLSLTools.h
src/sca/builtinResource.h)
@@ -72,8 +71,7 @@ set(SRCS
src/sca/GLSLTools.cpp
src/GLSLPostProcessor.cpp
src/ShaderMinifier.cpp
src/SpirvFixup.cpp
src/SpirvRemapWrapper.cpp)
src/SpirvFixup.cpp)
# ==================================================================================================
# Include and target definitions
+88 -50
View File
@@ -17,12 +17,12 @@
#include "GLSLPostProcessor.h"
#include <GlslangToSpv.h>
#include <SPVRemapper.h>
#include <spirv-tools/libspirv.hpp>
#include <spirv_glsl.hpp>
#include <spirv_msl.hpp>
#include "backend/DriverEnums.h"
#include "private/filament/DescriptorSets.h"
#include "sca/builtinResource.h"
#include "sca/GLSLTools.h"
@@ -44,10 +44,15 @@
#include <algorithm>
#include <optional>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include <stddef.h>
#include <stdint.h>
#ifdef FILAMENT_SUPPORTS_WEBGPU
#include <tint/tint.h>
#endif
@@ -70,22 +75,7 @@ using BindingIndexMap = std::unordered_map<std::string, uint16_t>;
#define DEBUG_LOG_DESCRIPTOR_SETS 0
#endif
const char* toString(DescriptorType type) {
switch (type) {
case DescriptorType::UNIFORM_BUFFER:
return "UNIFORM_BUFFER";
case DescriptorType::SHADER_STORAGE_BUFFER:
return "SHADER_STORAGE_BUFFER";
case DescriptorType::SAMPLER:
return "SAMPLER";
case DescriptorType::INPUT_ATTACHMENT:
return "INPUT_ATTACHMENT";
case DescriptorType::SAMPLER_EXTERNAL:
return "SAMPLER_EXTERNAL";
}
}
const char* toString(ShaderStageFlags flags) {
static const char* toString(ShaderStageFlags const flags) {
std::vector<const char*> stages;
if (any(flags & ShaderStageFlags::VERTEX)) {
stages.push_back("VERTEX");
@@ -110,14 +100,14 @@ const char* toString(ShaderStageFlags flags) {
return buffer;
}
const char* prettyDescriptorFlags(DescriptorFlags flags) {
static const char* prettyDescriptorFlags(DescriptorFlags const flags) {
if (flags == DescriptorFlags::DYNAMIC_OFFSET) {
return "DYNAMIC_OFFSET";
}
return "NONE";
}
const char* prettyPrintSamplerType(SamplerType type) {
static const char* prettyPrintSamplerType(SamplerType const type) {
switch (type) {
case SamplerType::SAMPLER_2D:
return "SAMPLER_2D";
@@ -144,12 +134,18 @@ DescriptorSetLayout getPerMaterialDescriptorSet(SamplerInterfaceBlock const& sib
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
+PerMaterialBindingPoints::MATERIAL_PARAMS, DescriptorFlags::NONE, 0 });
for (auto const& sampler : samplers) {
layout.bindings.push_back(DescriptorSetLayoutBinding {
(sampler.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) ?
DescriptorType::SAMPLER_EXTERNAL : DescriptorType::SAMPLER,
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, sampler.binding,
DescriptorFlags::NONE, 0 });
for (auto const& sampler: samplers) {
DescriptorSetLayoutBinding layoutBinding{
DescriptorType::SAMPLER_EXTERNAL,
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
sampler.binding,
DescriptorFlags::NONE,
0
};
if (sampler.type != SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) {
layoutBinding.type = descriptor_sets::getDescriptorType(sampler.type, sampler.format);
}
layout.bindings.push_back(layoutBinding);
}
return layout;
@@ -163,11 +159,12 @@ static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
DescriptorSetLayout const descriptorSetLayout = [&] {
switch (set) {
case DescriptorSetBindingPoints::PER_VIEW: {
bool const isLit = material.isLit || material.hasShadowMultiplier;
bool const isSSR = material.reflectionMode == ReflectionMode::SCREEN_SPACE ||
material.refractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(config.variantFilter & UserVariantFilterMask(UserVariantFilterBit::FOG));
return descriptor_sets::getPerViewDescriptorSetLayoutWithVariant(
config.variant, config.domain, config.variantFilter,
material.isLit || material.hasShadowMultiplier,
material.reflectionMode,
material.refractionMode);
config.variant, config.domain, isLit, isSSR, hasFog);
}
case DescriptorSetBindingPoints::PER_RENDERABLE:
return descriptor_sets::getPerRenderableLayout();
@@ -209,17 +206,16 @@ static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
return descriptor_sets::getDescriptorName(set, binding);
};
for (auto descriptor : descriptorSetLayout.bindings) {
descriptor_binding_t binding = descriptor.binding;
for (auto const& layoutBinding : descriptorSetLayout.bindings) {
descriptor_binding_t binding = layoutBinding.binding;
auto name = getDescriptorName(binding);
if (descriptor.type == DescriptorType::SAMPLER ||
descriptor.type == DescriptorType::SAMPLER_EXTERNAL) {
auto pos = std::find_if(descriptorSetSamplerList.begin(), descriptorSetSamplerList.end(),
if (DescriptorSetLayoutBinding::isSampler(layoutBinding.type)) {
auto const pos = std::find_if(descriptorSetSamplerList.begin(), descriptorSetSamplerList.end(),
[&](const auto& entry) { return entry.binding == binding; });
assert_invariant(pos != descriptorSetSamplerList.end());
descriptors.emplace_back(name, descriptor, *pos);
descriptors.emplace_back(name, layoutBinding, *pos);
} else {
descriptors.emplace_back(name, descriptor, std::nullopt);
descriptors.emplace_back(name, layoutBinding, std::nullopt);
}
}
@@ -228,8 +224,8 @@ static void collectDescriptorsForSet(DescriptorSetBindingPoints set,
});
}
void prettyPrintDescriptorSetInfoVector(DescriptorSets const& sets) {
auto getName = [](uint8_t set) {
static void prettyPrintDescriptorSetInfoVector(DescriptorSets const& sets) noexcept {
auto getName = [](uint8_t const set) {
switch (set) {
case +DescriptorSetBindingPoints::PER_VIEW:
return "perViewDescriptorSetLayout";
@@ -246,18 +242,23 @@ void prettyPrintDescriptorSetInfoVector(DescriptorSets const& sets) {
printf("[DS] info (%s) = [\n", getName(setIndex));
for (auto const& descriptor : descriptors) {
auto const& [name, info, sampler] = descriptor;
if (info.type == DescriptorType::SAMPLER ||
info.type == DescriptorType::SAMPLER_EXTERNAL) {
if (DescriptorSetLayoutBinding::isSampler(info.type)) {
assert_invariant(sampler.has_value());
printf(" {name = %s, binding = %d, type = %s, count = %d, stage = %s, flags = "
printf(" {name = %s, binding = %d, type = %.*s, count = %d, stage = %s, flags = "
"%s, samplerType = %s}",
name.c_str_safe(), info.binding, toString(info.type), info.count,
name.c_str_safe(), info.binding,
int(to_string(info.type).size()),
to_string(info.type).data(),
info.count,
toString(info.stageFlags), prettyDescriptorFlags(info.flags),
prettyPrintSamplerType(sampler->type));
} else {
printf(" {name = %s, binding = %d, type = %s, count = %d, stage = %s, flags = "
printf(" {name = %s, binding = %d, type = %.*s, count = %d, stage = %s, flags = "
"%s}",
name.c_str_safe(), info.binding, toString(info.type), info.count,
name.c_str_safe(), info.binding,
int(to_string(info.type).size()),
to_string(info.type).data(),
info.count,
toString(info.stageFlags), prettyDescriptorFlags(info.flags));
}
printf(",\n");
@@ -288,8 +289,24 @@ GLSLPostProcessor::GLSLPostProcessor(MaterialBuilder::Optimization optimization,
: mOptimization(optimization),
mPrintShaders(flags & PRINT_SHADERS),
mGenerateDebugInfo(flags & GENERATE_DEBUG_INFO) {
// This should occur only once, to avoid races.
SpirvRemapWrapperSetUp();
// SPIRV error handler registration needs to occur only once. To avoid a race we do it up here
// in the constructor, which gets invoked before MaterialBuilder kicks off jobs.
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
slog.e << str << io::endl;
});
// Similar to above, we need to do a no-op remap to init a static table in the remapper before
// the jobs start using remap().
spv::spirvbin_t remapper(0);
// We need to provide at least a valid header to not crash.
SpirvBlob spirv {
0x07230203,// MAGIC
0, // VERSION
0, // GENERATOR
0, // BOUND
0 // SCHEMA, must be 0
};
remapper.remap(spirv, 0);
}
GLSLPostProcessor::~GLSLPostProcessor() = default;
@@ -455,7 +472,25 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
break;
}
case DescriptorType::SAMPLER:
case DescriptorType::SAMPLER_2D_FLOAT:
case DescriptorType::SAMPLER_2D_INT:
case DescriptorType::SAMPLER_2D_UINT:
case DescriptorType::SAMPLER_2D_DEPTH:
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
case DescriptorType::SAMPLER_2D_ARRAY_INT:
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
case DescriptorType::SAMPLER_CUBE_FLOAT:
case DescriptorType::SAMPLER_CUBE_INT:
case DescriptorType::SAMPLER_CUBE_UINT:
case DescriptorType::SAMPLER_CUBE_DEPTH:
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
case DescriptorType::SAMPLER_3D_FLOAT:
case DescriptorType::SAMPLER_3D_INT:
case DescriptorType::SAMPLER_3D_UINT:
case DescriptorType::SAMPLER_EXTERNAL: {
assert_invariant(sampler.has_value());
const std::string samplerName = std::string(name.c_str()) + "Smplr";
@@ -551,7 +586,7 @@ bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
//After splitting the image samplers, we need to remap the bindings to separate them.
rebindImageSamplerForWGSL(*spirv);
//Allow non-uniform derivitives due to our nested shaders. See https://github.com/gpuweb/gpuweb/issues/3479
//Allow non-uniform derivatives due to our nested shaders. See https://github.com/gpuweb/gpuweb/issues/3479
const tint::spirv::reader::Options readerOpts{true};
tint::wgsl::writer::Options writerOpts{};
@@ -590,7 +625,9 @@ bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
*outWsl = wgslOut->wgsl;
return true;
#else
slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU and FILAMENT_SUPPORTS_WEBGPU" << io::endl;
slog.i << "Trying to emit WGSL without including WebGPU dependencies,"
" please set CMake arg FILAMENT_SUPPORTS_WEBGPU and FILAMENT_SUPPORTS_WEBGPU"
<< io::endl;
return false;
#endif
@@ -971,7 +1008,8 @@ void GLSLPostProcessor::optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv)
}
// Remove dead module-level objects: functions, types, vars
SpirvRemapWrapperRemap(spirv);
spv::spirvbin_t remapper(0);
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
}
void GLSLPostProcessor::fixupClipDistance(
-1
View File
@@ -23,7 +23,6 @@
#include <private/filament/SamplerInterfaceBlock.h>
#include "ShaderMinifier.h"
#include "SpirvRemapWrapper.h"
#include <spirv-tools/optimizer.hpp>
-54
View File
@@ -1,54 +0,0 @@
/*
* Copyright (C) 2017 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 "SpirvRemapWrapper.h"
#include <SPVRemapper.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <string>
namespace filamat {
void SpirvRemapWrapperSetUp() {
// SPIRV error handler registration should occur only once.
// Construct this SpirvRemapWrapper object only once.
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
utils::slog.e << str << utils::io::endl;
});
// Similar to above, we need to do a no-op remap to init a static
// table in the remapper before the jobs start using remap().
spv::spirvbin_t remapper(0);
// We need to provide at least a valid header to not crash.
std::vector<uint32_t> spirv {
0x07230203,// MAGIC
0, // VERSION
0, // GENERATOR
0, // BOUND
0 // SCHEMA, must be 0
};
remapper.remap(spirv, 0);
}
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv) {
// Remove dead module-level objects: functions, types, vars
spv::spirvbin_t remapper(0);
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
}
} // namespace filamat
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2017 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_SPIRVREMAPWRAPPER_H
#define TNT_SPIRVREMAPWRAPPER_H
#include <cstdint>
#include <vector>
namespace filamat {
void SpirvRemapWrapperSetUp();
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv);
} // namespace filamat
#endif //TNT_SPIRVREMAPWRAPPER_H
@@ -27,7 +27,10 @@
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utility>
@@ -194,11 +197,7 @@ void MaterialDescriptorBindingsChuck::flatten(Flattener& f) {
// all the material's sampler descriptors
for (auto const& entry: mSamplerInterfaceBlock.getSamplerInfoList()) {
f.writeString({ entry.uniformName.data(), entry.uniformName.size() });
if (entry.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) {
f.writeUint8(uint8_t(DescriptorType::SAMPLER_EXTERNAL));
} else {
f.writeUint8(uint8_t(DescriptorType::SAMPLER));
}
f.writeUint8(uint8_t(descriptor_sets::getDescriptorType(entry.type, entry.format)));
f.writeUint8(entry.binding);
}
}
@@ -228,11 +227,7 @@ void MaterialDescriptorSetLayoutChunk::flatten(Flattener& f) {
// all the material's sampler descriptors
for (auto const& entry: mSamplerInterfaceBlock.getSamplerInfoList()) {
if (entry.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) {
f.writeUint8(uint8_t(DescriptorType::SAMPLER_EXTERNAL));
} else {
f.writeUint8(uint8_t(DescriptorType::SAMPLER));
}
f.writeUint8(uint8_t(descriptor_sets::getDescriptorType(entry.type, entry.format)));
f.writeUint8(uint8_t(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT));
f.writeUint8(entry.binding);
f.writeUint8(uint8_t(DescriptorFlags::NONE));
+60 -55
View File
@@ -36,6 +36,7 @@
#include <algorithm>
#include <iterator>
#include <utility>
#include <stddef.h>
#include <stdint.h>
@@ -46,9 +47,9 @@ using namespace filament;
using namespace filament::backend;
using namespace utils;
void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream& out,
ShaderStage stage, MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, filament::Variant variant) noexcept {
void ShaderGenerator::generateSurfaceMaterialVariantDefines(io::sstream& out,
ShaderStage const stage, MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, filament::Variant const variant) noexcept {
bool const litVariants = material.isLit || material.hasShadowMultiplier;
@@ -228,25 +229,25 @@ void ShaderGenerator::generateSurfaceMaterialVariantProperties(io::sstream& out,
}
}
void ShaderGenerator::generateVertexDomainDefines(io::sstream& vs, VertexDomain domain) noexcept {
void ShaderGenerator::generateVertexDomainDefines(io::sstream& out, VertexDomain const domain) noexcept {
switch (domain) {
case VertexDomain::OBJECT:
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_OBJECT", true);
CodeGenerator::generateDefine(out, "VERTEX_DOMAIN_OBJECT", true);
break;
case VertexDomain::WORLD:
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_WORLD", true);
CodeGenerator::generateDefine(out, "VERTEX_DOMAIN_WORLD", true);
break;
case VertexDomain::VIEW:
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_VIEW", true);
CodeGenerator::generateDefine(out, "VERTEX_DOMAIN_VIEW", true);
break;
case VertexDomain::DEVICE:
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_DEVICE", true);
CodeGenerator::generateDefine(out, "VERTEX_DOMAIN_DEVICE", true);
break;
}
}
void ShaderGenerator::generatePostProcessMaterialVariantDefines(io::sstream& out,
PostProcessVariant variant) noexcept {
PostProcessVariant const variant) noexcept {
switch (variant) {
case PostProcessVariant::OPAQUE:
CodeGenerator::generateDefine(out, "POST_PROCESS_OPAQUE", 1u);
@@ -258,7 +259,7 @@ void ShaderGenerator::generatePostProcessMaterialVariantDefines(io::sstream& out
}
void ShaderGenerator::appendShader(io::sstream& ss,
const CString& shader, size_t lineOffset) noexcept {
const CString& shader, size_t const lineOffset) noexcept {
auto countLines = [](const char* s) -> size_t {
size_t lines = 0;
@@ -314,9 +315,9 @@ ShaderGenerator::ShaderGenerator(
MaterialBuilder::PreprocessorDefineList const& defines,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::PushConstantList const& pushConstants,
CString const& materialCode, size_t lineOffset,
CString const& materialVertexCode, size_t vertexLineOffset,
MaterialBuilder::MaterialDomain materialDomain) noexcept {
CString const& materialCode, size_t const lineOffset,
CString const& materialVertexCode, size_t const vertexLineOffset,
MaterialBuilder::MaterialDomain const materialDomain) noexcept {
if (materialDomain == MaterialBuilder::MaterialDomain::COMPUTE) {
// we shouldn't have a vertex shader in a compute material
@@ -360,8 +361,8 @@ ShaderGenerator::ShaderGenerator(
}
}
void ShaderGenerator::fixupExternalSamplers(ShaderModel sm, std::string& shader,
MaterialBuilder::FeatureLevel featureLevel,
void ShaderGenerator::fixupExternalSamplers(ShaderModel const sm, std::string& shader,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material) noexcept {
// External samplers are only supported on GL ES at the moment, we must
// skip the fixup on desktop targets
@@ -370,11 +371,11 @@ void ShaderGenerator::fixupExternalSamplers(ShaderModel sm, std::string& shader,
}
}
std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
MaterialInfo const& material, const filament::Variant variant, Interpolation interpolation,
VertexDomain vertexDomain) const noexcept {
std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel const shaderModel,
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material, const filament::Variant variant, Interpolation const interpolation,
VertexDomain const vertexDomain) const noexcept {
assert_invariant(filament::Variant::isValid(variant));
assert_invariant(mMaterialDomain != MaterialBuilder::MaterialDomain::COMPUTE);
@@ -416,23 +417,23 @@ std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel shaderModel,
AttributeBitset attributes = material.requiredAttributes;
if (hasSkinningOrMorphing(variant, featureLevel)) {
attributes.set(VertexAttribute::BONE_INDICES);
attributes.set(VertexAttribute::BONE_WEIGHTS);
attributes.set(BONE_INDICES);
attributes.set(BONE_WEIGHTS);
if (material.useLegacyMorphing) {
attributes.set(VertexAttribute::MORPH_POSITION_0);
attributes.set(VertexAttribute::MORPH_POSITION_1);
attributes.set(VertexAttribute::MORPH_POSITION_2);
attributes.set(VertexAttribute::MORPH_POSITION_3);
attributes.set(VertexAttribute::MORPH_TANGENTS_0);
attributes.set(VertexAttribute::MORPH_TANGENTS_1);
attributes.set(VertexAttribute::MORPH_TANGENTS_2);
attributes.set(VertexAttribute::MORPH_TANGENTS_3);
attributes.set(MORPH_POSITION_0);
attributes.set(MORPH_POSITION_1);
attributes.set(MORPH_POSITION_2);
attributes.set(MORPH_POSITION_3);
attributes.set(MORPH_TANGENTS_0);
attributes.set(MORPH_TANGENTS_1);
attributes.set(MORPH_TANGENTS_2);
attributes.set(MORPH_TANGENTS_3);
}
}
MaterialBuilder::PushConstantList vertexPushConstants;
std::copy_if(mPushConstants.begin(), mPushConstants.end(),
std::back_insert_iterator<MaterialBuilder::PushConstantList>(vertexPushConstants),
std::back_insert_iterator(vertexPushConstants),
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::VERTEX;
});
@@ -505,11 +506,11 @@ std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel shaderModel,
return vs.c_str();
}
std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel const shaderModel,
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material, const filament::Variant variant,
Interpolation interpolation, UserVariantFilterMask variantFilter) const noexcept {
Interpolation const interpolation, UserVariantFilterMask const variantFilter) const noexcept {
assert_invariant(filament::Variant::isValid(variant));
assert_invariant(mMaterialDomain != MaterialBuilder::MaterialDomain::COMPUTE);
@@ -529,8 +530,8 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
generateSurfaceMaterialVariantDefines(
fs, ShaderStage::FRAGMENT, featureLevel, material, variant);
auto defaultSpecularAO = shaderModel == ShaderModel::MOBILE ?
SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE;
auto const defaultSpecularAO = shaderModel == ShaderModel::MOBILE ?
SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE;
auto specularAO = material.specularAOSet ? material.specularAO : defaultSpecularAO;
CodeGenerator::generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO));
@@ -542,12 +543,12 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
MaterialBuilder::PushConstantList fragmentPushConstants;
std::copy_if(mPushConstants.begin(), mPushConstants.end(),
std::back_insert_iterator<MaterialBuilder::PushConstantList>(fragmentPushConstants),
std::back_insert_iterator(fragmentPushConstants),
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::FRAGMENT;
});
cg.generateSurfaceShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
fragmentPushConstants);
cg.generateSurfaceShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes,
interpolation, fragmentPushConstants);
CodeGenerator::generateSurfaceTypes(fs, ShaderStage::FRAGMENT);
@@ -605,12 +606,16 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
if (featureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
// this is the list of samplers we need to filter
bool const isLit = material.isLit || material.hasShadowMultiplier;
bool const isSSR = material.reflectionMode == ReflectionMode::SCREEN_SPACE ||
material.refractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(variantFilter & UserVariantFilterMask(UserVariantFilterBit::FOG));
auto const list = SamplerInterfaceBlock::filterSamplerList(
SibGenerator::getPerViewSib(variant).getSamplerInfoList(),
descriptor_sets::getPerViewDescriptorSetLayoutWithVariant(
variant, mMaterialDomain, variantFilter,
material.isLit || material.hasShadowMultiplier,
material.reflectionMode, material.refractionMode));
variant, mMaterialDomain, isLit, isSSR, hasFog));
cg.generateCommonSamplers(fs, DescriptorSetBindingPoints::PER_VIEW, list);
}
@@ -665,9 +670,9 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel shaderMode
return fs.c_str();
}
std::string ShaderGenerator::createSurfaceComputeProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
std::string ShaderGenerator::createSurfaceComputeProgram(ShaderModel const shaderModel,
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material) const noexcept {
assert_invariant(mMaterialDomain == MaterialBuilder::MaterialDomain::COMPUTE);
assert_invariant(featureLevel >= FeatureLevel::FEATURE_LEVEL_2);
@@ -708,9 +713,9 @@ std::string ShaderGenerator::createSurfaceComputeProgram(filament::backend::Shad
return s.c_str();
}
std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel const sm,
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material, const filament::Variant::type_t variantKey) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage, featureLevel);
io::sstream vs;
@@ -718,7 +723,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
generateUserSpecConstants(cg, vs, mConstants);
CodeGenerator::generateDefine(vs, "LOCATION_POSITION", uint32_t(VertexAttribute::POSITION));
CodeGenerator::generateDefine(vs, "LOCATION_POSITION", uint32_t(POSITION));
// custom material variables
size_t variableIndex = 0;
@@ -752,9 +757,9 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm,
return vs.c_str();
}
std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialBuilder::FeatureLevel featureLevel,
std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel const sm,
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
MaterialBuilder::FeatureLevel const featureLevel,
MaterialInfo const& material, uint8_t variant) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage, featureLevel);
io::sstream fs;
@@ -811,7 +816,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm,
}
bool ShaderGenerator::hasSkinningOrMorphing(
filament::Variant variant, MaterialBuilder::FeatureLevel featureLevel) noexcept {
filament::Variant const variant, MaterialBuilder::FeatureLevel const featureLevel) noexcept {
return variant.hasSkinningOrMorphing()
// HACK(exv): Ignore skinning/morphing variant when targeting ESSL 1.0. We should
// either properly support skinning on FL0 or build a system in matc which allows
@@ -820,7 +825,7 @@ bool ShaderGenerator::hasSkinningOrMorphing(
}
bool ShaderGenerator::hasStereo(
filament::Variant variant, MaterialBuilder::FeatureLevel featureLevel) noexcept {
filament::Variant const variant, MaterialBuilder::FeatureLevel const featureLevel) noexcept {
return variant.hasStereo()
// HACK(exv): Ignore stereo variant when targeting ESSL 1.0. We should properly build a
// system in matc which allows the set of included variants to differ per-feature level.
+72 -17
View File
@@ -23,6 +23,7 @@
#include <utils/ostream.h>
#include <string_view>
#include <utility>
#include <assert.h>
#include <stddef.h>
@@ -97,11 +98,7 @@ public:
return *this;
}
~CString() noexcept {
if (mData) {
free(mData - 1);
}
}
~CString() noexcept;
void swap(CString& other) noexcept {
// don't use std::swap(), we don't want an STL dependency in this file
@@ -110,8 +107,8 @@ public:
other.mCStr = temp;
}
const_pointer c_str() const noexcept { return mCStr; }
pointer c_str() noexcept { return mCStr; }
const_pointer c_str() const noexcept { return const_cast<CString*>(this)->c_str(); }
const_pointer c_str_safe() const noexcept { return mData ? c_str() : ""; }
const_pointer data() const noexcept { return c_str(); }
pointer data() noexcept { return c_str(); }
@@ -119,33 +116,89 @@ public:
size_type length() const noexcept { return size(); }
bool empty() const noexcept { return size() == 0; }
iterator begin() noexcept { return mCStr; }
iterator begin() noexcept { return c_str(); }
iterator end() noexcept { return begin() + length(); }
const_iterator begin() const noexcept { return data(); }
const_iterator end() const noexcept { return begin() + length(); }
const_iterator cbegin() const noexcept { return begin(); }
const_iterator cend() const noexcept { return end(); }
CString& replace(size_type pos, size_type len, const CString& str) noexcept;
CString& insert(size_type pos, const CString& str) noexcept { return replace(pos, 0, str); }
CString& append(const CString& str) noexcept { return insert(length(), str); }
// replace
template<size_t N>
CString& replace(size_type const pos,
size_type const len, const StringLiteral<N>& str) & noexcept {
return replace(pos, len, str, N - 1);
}
const_reference operator[](size_type pos) const noexcept {
CString& replace(size_type const pos, size_type const len, const CString& str) & noexcept {
return replace(pos, len, str.c_str_safe(), str.size());
}
template<size_t N>
CString&& replace(size_type const pos,
size_type const len, const StringLiteral<N>& str) && noexcept {
return std::move(replace(pos, len, str));
}
CString&& replace(size_type const pos, size_type const len, const CString& str) && noexcept {
return std::move(replace(pos, len, str));
}
// insert
template<size_t N>
CString& insert(size_type const pos, const StringLiteral<N>& str) & noexcept {
return replace(pos, 0, str);
}
CString& insert(size_type const pos, const CString& str) & noexcept {
return replace(pos, 0, str);
}
template<size_t N>
CString&& insert(size_type const pos, const StringLiteral<N>& str) && noexcept {
return std::move(*this).replace(pos, 0, str);
}
CString&& insert(size_type const pos, const CString& str) && noexcept {
return std::move(*this).replace(pos, 0, str);
}
// append
template<size_t N>
CString& append(const StringLiteral<N>& str) & noexcept {
return insert(length(), str);
}
CString& append(const CString& str) & noexcept {
return insert(length(), str);
}
template<size_t N>
CString&& append(const StringLiteral<N>& str) && noexcept {
return std::move(*this).insert(length(), str);
}
CString&& append(const CString& str) && noexcept {
return std::move(*this).insert(length(), str);
}
const_reference operator[](size_type const pos) const noexcept {
assert(pos < size());
return begin()[pos];
}
reference operator[](size_type pos) noexcept {
reference operator[](size_type const pos) noexcept {
assert(pos < size());
return begin()[pos];
}
const_reference at(size_type pos) const noexcept {
const_reference at(size_type const pos) const noexcept {
assert(pos < size());
return begin()[pos];
}
reference at(size_type pos) noexcept {
reference at(size_type const pos) noexcept {
assert(pos < size());
return begin()[pos];
}
@@ -171,7 +224,7 @@ public:
}
// placement new declared as "throw" to avoid the compiler's null-check
inline void* operator new(size_t, void* ptr) {
void* operator new(size_t, void* ptr) {
assert(ptr);
return ptr;
}
@@ -185,6 +238,8 @@ public:
};
private:
CString& replace(size_type pos, size_type len, char const* str, size_t l) & noexcept;
#if !defined(NDEBUG)
friend io::ostream& operator<<(io::ostream& out, const CString& rhs);
#endif
@@ -225,7 +280,7 @@ private:
}
};
// implement this for your type for automatic conversion to CString. Failing to do so leads
// Implement this for your type for automatic conversion to CString. Failing to do so leads
// to a compile-time failure.
template<typename T>
CString to_string(T value) noexcept;
@@ -249,7 +304,7 @@ public:
pointer c_str() noexcept { return mData; }
private:
value_type mData[N] = {0};
value_type mData[N] = {};
};
} // namespace utils
+25 -16
View File
@@ -20,27 +20,30 @@
#include <utils/ostream.h>
#include <algorithm>
#include <cstdlib>
#include <memory>
namespace utils {
UTILS_NOINLINE
CString::CString(const char* cstr, size_t length) {
CString::CString(const char* cstr, size_t const length) {
if (length && cstr) {
Data* p = (Data*)malloc(sizeof(Data) + length + 1);
p->length = (size_type)length;
mCStr = (value_type*)(p + 1);
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + length + 1));
p->length = size_type(length);
mCStr = reinterpret_cast<value_type*>(p + 1);
// we don't use memcpy here to avoid a call to libc, the generated code is pretty good.
std::uninitialized_copy_n(cstr, length, mCStr);
mCStr[length] = '\0';
}
}
CString::CString(size_t length) {
CString::CString(size_t const length) {
if (length) {
Data* p = (Data*)malloc(sizeof(Data) + length + 1);
p->length = (size_type)length;
mCStr = (value_type*)(p + 1);
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + length + 1));
p->length = size_type(length);
mCStr = reinterpret_cast<value_type*>(p + 1);
std::fill_n(mCStr, length, 0);
mCStr[length] = '\0';
}
@@ -58,24 +61,30 @@ CString& CString::operator=(const CString& rhs) {
if (this != &rhs) {
auto *const p = mData ? mData - 1 : nullptr;
new(this) CString(rhs);
free(p);
std::free(p);
}
return *this;
}
CString& CString::replace(size_type pos, size_type len, const CString& str) noexcept {
CString::~CString() noexcept {
if (mData) {
std::free(mData - 1);
}
}
CString& CString::replace(size_type const pos, size_type len, char const* str, size_t const l) & noexcept {
assert(pos <= size());
len = std::min(len, size() - pos);
// The new size of the string, after the replacement.
const size_type newSize = size() - len + str.size();
const size_type newSize = size() - len + l;
// Allocate enough memory to hold the new string.
Data* p = (Data*) malloc(sizeof(Data) + newSize + 1);
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + newSize + 1));
assert(p);
p->length = newSize;
value_type* newStr = (value_type*) (p + 1);
value_type* newStr = reinterpret_cast<value_type*>(p + 1);
const value_type* beginning = mCStr;
const value_type* replacementStart = mCStr + pos;
@@ -84,7 +93,7 @@ CString& CString::replace(size_type pos, size_type len, const CString& str) noex
value_type* ptr = newStr;
ptr = std::uninitialized_copy(beginning, replacementStart, ptr);
ptr = std::uninitialized_copy_n(str.c_str_safe(), str.length(), ptr);
ptr = std::uninitialized_copy_n(str, l, ptr);
ptr = std::uninitialized_copy(replacementEnd, end, ptr);
// null-terminator
@@ -92,14 +101,14 @@ CString& CString::replace(size_type pos, size_type len, const CString& str) noex
std::swap(mCStr, newStr);
if (newStr) {
free((Data*) newStr - 1);
std::free(reinterpret_cast<Data*>(newStr) - 1);
}
return *this;
}
#if !defined(NDEBUG)
io::ostream& operator<<(io::ostream& out, const utils::CString& rhs) {
io::ostream& operator<<(io::ostream& out, const CString& rhs) {
return out << rhs.c_str_safe();
}
#endif
+2 -2
View File
@@ -700,7 +700,8 @@ constexpr ToneMapper* createToneMapper(const ColorGradingSettings& settings) noe
}
ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine) {
ToneMapper* toneMapper = createToneMapper(settings);
ToneMapper* toneMapperRaw = createToneMapper(settings);
std::shared_ptr<ToneMapper> toneMapper(toneMapperRaw);
ColorGrading *colorGrading = ColorGrading::Builder()
.quality(settings.quality)
.exposure(settings.exposure)
@@ -723,7 +724,6 @@ ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* e
.gamutMapping(settings.gamutMapping)
.outputColorSpace(settings.colorspace)
.build(*engine);
delete toneMapper;
return colorGrading;
}
+80 -17
View File
@@ -1,14 +1,42 @@
# 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.
import os
import shutil
import re
from utils import execute, ArgParseImpl
from utils import execute, ArgParseImpl, mkdir_p
GOLDENS_DIR = 'renderdiff'
ACCESS_TYPE_TOKEN = 'token'
ACCESS_TYPE_SSH = 'ssh'
ACCESS_TYPE_READ_ONLY = 'read-only'
def _read_git_config(curdir):
with open(os.path.join(curdir, './.git/config'), 'r') as f:
return f.read()
def _write_git_config(curdir, config_str):
with open(os.path.join(curdir, './.git/config'), 'w') as f:
return f.write(config_str)
class GoldenManager:
def __init__(self, working_dir, access_token=None):
def __init__(self, working_dir, access_type=ACCESS_TYPE_READ_ONLY, access_token=None):
self.working_dir_ = working_dir
self.access_token_ = access_token
self.access_type_ = access_type
assert os.path.isdir(self.working_dir_),\
f"working directory {self.working_dir_} does not exist"
self._prepare()
@@ -16,16 +44,36 @@ class GoldenManager:
def _assets_dir(self):
return os.path.join(self.working_dir_, "filament-assets")
# Returns the directory containing the goldens
def directory(self):
return os.path.join(self._assets_dir(), GOLDENS_DIR)
def _get_repo_url(self):
protocol = ''
protocol_separator = ''
if self.access_type_ == ACCESS_TYPE_SSH:
protocol = 'git@'
protocol_separator = ':'
else:
protocol = 'https://' + \
(f'x-access-token:{self.access_token_}@' if self.access_token_ else '')
protocol_separator = '/'
return f'{protocol}github.com{protocol_separator}google/filament-assets.git'
def _prepare(self):
assets_dir = self._assets_dir()
if not os.path.exists(assets_dir):
access_token_part = ''
if self.access_token_:
access_token_part = f'x-access-token:{self.access_token_}@'
execute(
f'git clone --depth=1 https://{access_token_part}github.com/google/filament-assets.git',
cwd=self.working_dir_)
f'git clone --depth=1 {self._get_repo_url()}',
cwd=self.working_dir_,
capture_output=False
)
else:
if self.access_type_ == ACCESS_TYPE_SSH:
config = _read_git_config(self._assets_dir())
https_url = r'https://github\.com\/google\/filament\.git'
config = re.sub(https_url, self._get_repo_url(), config)
_write_git_config(self._assets_dir(), config)
self.update()
def update(self):
@@ -41,31 +89,46 @@ class GoldenManager:
assets_dir = self._assets_dir()
self._git_exec(f'checkout main')
self._git_exec(f'merge --no-ff {branch}')
if push_to_remote and self.access_token_:
if push_to_remote and \
(self.access_token_ or self.access_type_ == ACCESS_TYPE_SSH):
self._git_exec(f'push origin main')
self.update()
def source_from_and_commit(self, src_dir, commit_msg, branch, push_to_remote=False):
def source_from(self, src_dir, commit_msg, branch,
updates=[], deletes=[], push_to_remote=False):
assets_dir = self._assets_dir()
self._git_exec(f'checkout main')
# Force create the branch (note will overwrite the old branch)
self._git_exec(f'switch -C {branch}')
rdiff_dir = os.path.join(assets_dir, GOLDENS_DIR)
execute(f'rm -rf {rdiff_dir}')
execute(f'mkdir -p {rdiff_dir}')
shutil.copytree(src_dir, rdiff_dir, dirs_exist_ok=True)
self._git_exec(f'add {GOLDENS_DIR}')
if len(updates) == 0 and len(deletes) == 0:
shutil.rmtree(rdiff_dir, ignore_errors=True)
mkdir_p(rdiff_dir)
shutil.copytree(src_dir, rdiff_dir, dirs_exist_ok=True)
self._git_exec(f'add {GOLDENS_DIR}')
else:
for f in deletes:
self._git_exec(f'remove {os.path.join(GOLDENS_DIR, f)}')
for f in updates:
shutil.copy2(
os.path.join(src_dir, f),
os.path.join(rdiff_dir, f))
self._git_exec(f'add {os.path.join(GOLDENS_DIR, f)}')
TMP_GOLDEN_COMMIT_FILE = '/tmp/golden_commit.txt'
with open(TMP_GOLDEN_COMMIT_FILE, 'w') as f:
f.write(commit_msg)
self._git_exec(f'commit -F {TMP_GOLDEN_COMMIT_FILE}')
if push_to_remote and self.access_token_:
self._git_exec(f'push -f origin ${branch}')
self._git_exec(f'commit -a -F {TMP_GOLDEN_COMMIT_FILE}')
if push_to_remote and \
(self.access_token_ or self.access_type_ == ACCESS_TYPE_SSH):
self._git_exec(f'push -f origin {branch}')
self.update()
def download_to(self, dest_dir, branch='main'):
self._git_exec(f'checkout {branch}')
assets_dir = self._assets_dir()
execute(f'mkdir -p {dest_dir}')
mkdir_p(dest_dir)
rdiff_dir = os.path.join(assets_dir, GOLDENS_DIR)
shutil.copytree(rdiff_dir, dest_dir, dirs_exist_ok=True)
+14
View File
@@ -1,3 +1,17 @@
# 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.
import tifffile
import numpy
+12 -9
View File
@@ -16,8 +16,9 @@ import sys
import os
import json
import glob
import shutil
from utils import execute, ArgParseImpl
from utils import execute, ArgParseImpl, mkdir_p, mv_f
from parse_test_json import parse_test_config_from_path
from golden_manager import GoldenManager
from image_diff import same_image
@@ -46,7 +47,7 @@ def run_test(gltf_viewer,
assert os.access(gltf_viewer, os.X_OK)
named_output_dir = os.path.join(output_dir, test_config.name)
execute(f'mkdir -p {named_output_dir}')
mkdir_p(named_output_dir)
results = []
for test in test_config.tests:
@@ -82,9 +83,8 @@ def run_test(gltf_viewer,
result = RESULT_OK
out_tif_basename = f'{out_name}.tif'
out_tif_name = f'{named_output_dir}/{out_tif_basename}'
execute(f'mv -f {test.name}0.tif {out_tif_name}', capture_output=False)
execute(f'mv -f {test.name}0.json {named_output_dir}/{test.name}.json',
capture_output=False)
mv_f(f'{test.name}0.tif', out_tif_name)
mv_f(f'{test.name}0.json', f'{named_output_dir}/{test.name}.json')
else:
result = RESULT_FAILED_TO_RENDER
important_print(f'{test_desc} rendering failed with error={out_code}')
@@ -132,11 +132,12 @@ if __name__ == "__main__":
opengl_lib=args.opengl_lib,
vk_icd=args.vk_icd)
do_compare = False
# The presence of this argument indicates comparison against a set of goldens.
if args.golden_branch:
# prepare goldens working directory
tmp_golden_dir = '/tmp/renderdiff-goldens'
execute(f'mkdir -p {tmp_golden_dir}')
mkdir_p(tmp_golden_dir)
# Download the golden repo into the current working directory
golden_manager = GoldenManager(os.getcwd())
@@ -147,13 +148,15 @@ if __name__ == "__main__":
glob.glob(f'{os.path.join(tmp_golden_dir, test.name)}/**/*.tif', recursive=True)
}
results = compare_goldens(results, output_dir, goldens)
do_compare = True
with open(f'{output_dir}/results.json', 'w') as f:
f.write(json.dumps(results))
execute(f'cp {args.test} {output_dir}/test.json')
shutil.copy2(args.test, f'{output_dir}/test.json')
failed = [f" {k['name']}" for k in results if k['result'] != RESULT_OK]
success_count = len(results) - len(failed)
important_print(f'Successfully tested {success_count} / {len(results)}' +
op = 'tested' if do_compare else 'rendered'
important_print(f'Successfully {op} {success_count} / {len(results)}' +
('\nFailed:\n' + ('\n'.join(failed)) if len(failed) > 0 else ''))
+171
View File
@@ -0,0 +1,171 @@
# 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.
import sys
import os
import glob
import time
from golden_manager import GoldenManager, ACCESS_TYPE_SSH, ACCESS_TYPE_TOKEN
from image_diff import same_image
from utils import execute, ArgParseImpl
from utils import prompt_helper, PROMPT_YES, PROMPT_NO
def line_prompt(prompt, validator=lambda a:True):
while True:
res = input(f'{prompt} => ').strip()
if validator(res):
return res
return None
CONFIG_NEW_SRC_DIR = 'goldens_dir'
CONFIG_GOLDENS_BRANCH = 'goldens_branch'
CONFIG_GOLDENS_UPDATES = 'goldens_updates'
CONFIG_GOLDENS_DELETES = 'goldens_deletes'
CONFIG_AUTO_COMMIT = 'auto-commit'
CONFIG_COMMIT_MSG = 'commit_msg'
def _get_current_branch():
code, res = execute('git branch --show-current')
return res.strip()
def _file_as_str(fpath):
with open(fpath, 'r') as f:
return f.read()
def _do_update(golden_manager, config):
deletes = config[CONFIG_GOLDENS_DELETES]
updates = config[CONFIG_GOLDENS_UPDATES]
if len(deletes) == 0 and len(updates) == 0:
print('Nothing to update. Exiting...')
exit(0)
branch = config[CONFIG_GOLDENS_BRANCH]
src_dir = config[CONFIG_NEW_SRC_DIR]
auto_commit = config[CONFIG_AUTO_COMMIT]
commit_msg = config[CONFIG_COMMIT_MSG]
golden_manager.source_from(src_dir, commit_msg, branch,
updates=updates,
deletes=deletes,
push_to_remote=auto_commit)
def _get_deletes_updates(update_dir, golden_dir):
ret_delete = []
ret_update = []
for ext in ['tif', 'json']:
base = set(glob.glob(f'./**/*.{ext}', root_dir=golden_dir, recursive=True))
new = set(glob.glob(f'./**/*.{ext}', root_dir=update_dir, recursive=True))
delete = list(base - new)
update = list(new - base)
for fpath in base.intersection(new):
base_fpath = os.path.join(golden_dir, fpath)
new_fpath = os.path.join(update_dir, fpath)
if (ext == 'tif' and not same_image(new_fpath, base_fpath)) or \
(ext == 'json' and _file_as_str(new_fpath) != _file_as_str(base_fpath)):
update.append(fpath)
ret_update += update
ret_delete += delete
return ret_delete, ret_update
# Ask a bunch of questions to gather the configuration for the update
def _interactive_mode(base_golden_dir):
config = {}
cur_branch = _get_current_branch()
if prompt_helper(
f'Generate the new goldens from your local ' \
f'Filament branch? (branch={cur_branch})') == PROMPT_YES:
code, res = execute('bash ./test/renderdiff/test.sh generate',
capture_output=False)
if code != 0:
print('Failed to generate new goldens')
exit(1)
config[CONFIG_NEW_SRC_DIR] = os.path.join(os.getcwd(), './out/renderdiff_tests/')
else:
def validator(src_dir):
if not os.path.exists(src_dir):
print(f'Cannot find directory {src_dir}. Please try again.')
return False
return True
config[CONFIG_NEW_SRC_DIR] = line_prompt(
'Please provide path of directory containing new goldens',
validator)
if prompt_helper(f'Update new goldens to branch={cur_branch}? '
'(Note that this refers to a branch in the goldens repo, not the Filament repo.)'
) == PROMPT_YES:
config[CONFIG_GOLDENS_BRANCH] = cur_branch
else:
config[CONFIG_GOLDENS_BRANCH] = line_prompt('Please provide new branch name for update')
if prompt_helper(f'Provide a commit message?') == PROMPT_YES:
config[CONFIG_COMMIT_MSG] = line_prompt('Message:')
else:
config[CONFIG_COMMIT_MSG] = f'Update {time.time()} from filament ({cur_branch})'
new_golden_dir = config[CONFIG_NEW_SRC_DIR]
deletes, updates = _get_deletes_updates(new_golden_dir, base_golden_dir)
if len(deletes) + len(updates) != 0:
prompt = 'The following files will be changed:\n' + \
'\n'.join([f' {fname} [delete]' for fname in deletes]) + \
'\n'.join([f' {fname} [update]' for fname in updates]) + \
'\nIs that ok?'
if prompt_helper(prompt) == PROMPT_YES:
config[CONFIG_GOLDENS_DELETES] = deletes
config[CONFIG_GOLDENS_UPDATES] = updates
else:
# We cannot proceed if user answered no.
exit(1)
else:
config[CONFIG_GOLDENS_DELETES] = []
config[CONFIG_GOLDENS_UPDATES] = []
config[CONFIG_AUTO_COMMIT] = \
prompt_helper(f'Commit golden repo changes to remote?') == PROMPT_YES
return config
if __name__ == "__main__":
parser = ArgParseImpl()
parser.add_argument('--branch', help='Branch of the golden repo to write to')
parser.add_argument('--source', help='Directory containing the new goldens')
parser.add_argument('--commit-msg', help='Message for the commit to the golden repo')
parser.add_argument('--golden-repo-token', help='Access token for the golden repo')
args, _ = parser.parse_known_args(sys.argv[1:])
config = {}
golden_manager = GoldenManager(
os.getcwd(),
access_type=ACCESS_TYPE_SSH if not args.golden_repo_token else ACCESS_TYPE_TOKEN,
access_token=args.golden_repo_token
)
base_golden_dir = golden_manager.directory()
if args.branch and args.source and args.commit_msg:
assert os.path.exists(args.source), f'{args.source} (--source) directory not found'
deletes, updates = _get_deletes_updates(args.source, base_golden_dir)
config = {
CONFIG_AUTO_COMMIT: True,
CONFIG_GOLDENS_BRANCH: args.branch,
CONFIG_NEW_SRC_DIR: args.source,
CONFIG_GOLDENS_UPDATES: updates,
CONFIG_GOLDENS_DELETES: deletes,
CONFIG_COMMIT_MSG: args.commit_msg,
}
else:
config = _interactive_mode(base_golden_dir)
_do_update(golden_manager, config)
+40
View File
@@ -16,6 +16,7 @@ import subprocess
import os
import argparse
import sys
import pathlib
def execute(cmd,
cwd=None,
@@ -66,3 +67,42 @@ class ArgParseImpl(argparse.ArgumentParser):
sys.stderr.write('error: %s\n' % message)
self.print_help()
sys.exit(1)
PROMPT_YES = 'y'
PROMPT_NO = 'n'
PROMPT_YES_NO = f'{PROMPT_YES}{PROMPT_NO}'
class GetCh:
def __init__(self):
pass
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
getch = GetCh()
def prompt_helper(prompt_str, keys=PROMPT_YES_NO):
while True:
print(f'{prompt_str}: [' + ', '.join(keys) + '] => ', end='', flush=True)
val = getch()
print(val)
if val in keys or ord(val) == 3: # If user pressed Ctrl+c
if ord(val) == 3:
exit(1)
return val
def mkdir_p(path_str):
pathlib.Path(path_str).mkdir(parents=True, exist_ok=True)
def mv_f(src_str, dst_str):
src = pathlib.Path(src_str)
src.replace(dst_str)
+14 -4
View File
@@ -17,19 +17,29 @@ from utils import execute
def get_last_commit():
res, o = execute('git log -1')
commit, author, date, _, title, *desc = o.split('\n')
commit = commit.split(' ')[1]
title = title.strip()
desc = [l.strip() for l in desc[1:]]
if len(desc) > 0 and len(desc[0]) == 0:
while len(desc) > 0 and len(desc[0]) == 0:
desc = desc[1:]
return (
commit.split(' ')[1],
title.strip(),
commit,
title,
desc
)
def sanitized_split(line, split_atom='\n'):
return list(filter(lambda x: len(x) > 0, map(lambda x: x.strip(), line.split(split_atom))))
return list(
filter(
lambda x: len(x) > 0,
map(
lambda x: x.strip(),
line.split(split_atom)
)
)
)
RDIFF_UPDATE_GOLDEN_STR = 'RDIFF_UPDATE_GOLDEN'
+40 -8
View File
@@ -16,8 +16,9 @@
OUTPUT_DIR="$(pwd)/out/renderdiff_tests"
RENDERDIFF_TEST_DIR="$(pwd)/test/renderdiff"
TEST_UTILS_DIR="$(pwd)/test/utils"
BUILD_COMMON_DIR="$(pwd)/build/common"
MESA_DIR="$(pwd)/mesa/out/"
VENV_DIR="$(pwd)/venv"
os_name=$(uname -s)
if [[ "$os_name" == "Linux" ]]; then
@@ -29,9 +30,33 @@ else
exit 1
fi
function prepare_mesa() {
if [ ! -d ${MESA_LIB_DIR} ]; then
bash ${TEST_UTILS_DIR}/get_mesa.sh
function start_() {
if [[ "$GITHUB_WORKFLOW" ]]; then
set -ex
else
if [ ! -d ${MESA_LIB_DIR} ]; then
bash ${BUILD_COMMON_DIR}/get-mesa.sh
fi
# Install python deps
python3 -m venv ${VENV_DIR}
source ${VENV_DIR}/bin/activate
NEEDED_PYTHON_DEPS=("numpy" "tifffile")
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
if ! python3 -m pip show -q "${cmd}"; then
python3 -m pip install ${cmd}
fi
done
fi
}
function end_() {
if [[ "$GITHUB_WORKFLOW" ]]; then
set +ex
else
deactivate # End python virtual env
fi
}
@@ -41,12 +66,19 @@ function prepare_mesa() {
# - Run the python script that runs the test
# - Zip up the result
set -ex && prepare_mesa && \
GOLDEN_BRANCH_PARAM='--golden_branch=main'
if [ "$1" == "generate" ]; then
GOLDEN_BRANCH_PARAM=''
fi
start_ && \
mkdir -p ${OUTPUT_DIR} && \
CXX=`which clang++` CC=`which clang` ./build.sh -f -X ${MESA_DIR} -p desktop debug gltf_viewer && \
python3 ${RENDERDIFF_TEST_DIR}/src/run.py \
CXX=`which clang++` CC=`which clang` ./build.sh -f -X ${MESA_DIR} -p desktop debug gltf_viewer && \
python3 ${RENDERDIFF_TEST_DIR}/src/run.py \
--gltf_viewer="$(pwd)/out/cmake-debug/samples/gltf_viewer" \
--test=${RENDERDIFF_TEST_DIR}/tests/presubmit.json \
--output_dir=${OUTPUT_DIR} \
--opengl_lib=${MESA_LIB_DIR} \
--golden_branch=main
${GOLDEN_BRANCH_PARAM} && \
end_
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.60.0",
"version": "1.59.5",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",