Compare commits

...
Author SHA1 Message Date
bridgewaterrobbie f366ac3a35 Experiment: Avoid << on non uint to make tint happy 2025-03-28 16:31:30 -04:00
bridgewaterrobbie f78770c7fb Hacky OpName approach to bindings 2025-03-28 16:30:45 -04:00
bridgewaterrobbie feca632486 Output failing processed spir-v on failure to read with tint 2025-03-26 18:17:32 -04:00
bridgewaterrobbie 68652347b3 Implement combined image sampler separation, with one workaround for the binding splitter. 2025-03-26 18:17:24 -04:00
bridgewaterrobbie 585c10d9ba Allow non uniform derivitives 2025-03-26 18:10:39 -04:00
bridgewaterrobbie 7e7a481320 Hack a workaround for OpConstantLoad issue in Tint to work with most spec constants 2025-03-26 18:10:25 -04:00
bridgewaterrobbie b9a6cc5462 Workaround Tint issues with texelFetchOffset in dofMedian.mat 2025-03-26 18:10:25 -04:00
bridgewaterrobbie 755912e676 Update SPIR-V tools to commit ada1771a9f7a125573aa94fe551fdc44b45769bd to pull in splitter pass 2025-03-26 18:10:25 -04:00
Powei Feng 42ce76e285 Update MaterialVersion to 58 2025-03-26 10:56:33 -07:00
Doris Wu f903683c92 Pass the fgviewer gradle option (#8565) 2025-03-26 14:12:59 +08:00
Powei Feng 546ba48043 Fix test breaking changes with workarounds (#8569)
- Some tests require textures larger than 2048. Change the minimum
  to 4096 for now, and file proper bugs for tests.
- The introduction of uint8_t to DescriptorSetLayoutBinding
  caused unintended padding with using this struct as a hash key.
  We comment out the relevent code for now.
2025-03-25 16:11:35 -07:00
Powei Feng c81af315b2 engine: Add 1D LUT feature flag (#8568)
Note that the flag is default to false while we roll out this
feature.
2025-03-25 15:52:52 -07:00
rafadevai ea64db4218 vk: Fix Vulkan protected memory checks (#8561)
Set the support for isProtectedTexturesSupported
depending if the context supports protected content.

Fix checking if the protected feature is supported
on the host after retrieving the results from querying
the Physical Device.
2025-03-25 20:04:42 +00:00
alizahlalani 0c8df766d0 make createExternalImage UTILS_PUBLIC across platforms for future proofing (#8547) 2025-03-24 11:18:38 -07:00
Mathias Agopian 8f58743405 support up to five custom varyings
Five custom variables (varyings) are now available on the condition that
the `color` attribute is not requested.

FIXES=[404930099]
2025-03-24 09:38:31 -07:00
Syed Idris Shah af079b42a6 Make decl/def of createDriver api consistent
Replace "void* const" with "void*" as const here serves no purpose because of following reasons:
  1. void* const in function parameter has a limited and local effect on the code.
  2. clang tidy would complain and report error if const is added to the function declaration.
  3. const is dropped later in the call stack making the code incosistent.
2025-03-21 13:44:10 -04:00
rafadevai 7f7bceb970 vk: New method to describe external image in Vulkan Android (#8551)
To match the GL platform add a new function to describe
an external image.

Also make `ExternalImageVulkanAndroid` and
`getExternalImageMetadata` protected, so only the
backend has access to it.
2025-03-21 17:09:29 +00:00
Powei Feng 625603d8d4 vk: split layout cache from descriptorSet cache (#8554)
This is just splitting the layout cache into its own class and
files.
2025-03-21 16:33:35 +00:00
Doris Wu d2d5d62a20 Some cleanups (#8558)
* Clean up includes

* Fix the logic
2025-03-22 00:17:22 +08:00
Doris Wu 5e9be5dd2d Remove trailing whitespace (#8556) 2025-03-21 02:10:05 +00:00
Powei Feng df897b3fb2 osmesa: Enable Mesa/OSMesa rendering for mac (#8530)
This commit enables local running of the renderdiff tests and also
for github workflows.
2025-03-20 22:37:23 +00:00
Powei Feng 8c396caba0 vk: removing caching/ directory (#8553)
Move the files out of that directory for consistency. (Should have
never created the directory in the first place).

Also did some small clean-ups of removing old comments and no
longer needed includes.
2025-03-20 22:03:08 +00:00
Mathias AgopianandPowei Feng 6b91f30389 Materials can now specify a shadow attenuation factor (#8540)
* Materials can now specify a shadow strength factor

Materials have a new property: shadowStrength that can be used to
attenuate all shadows received by this material. e.g.:

```
void material(inout MaterialInputs material) {
  prepareMaterial(material);
  material. shadowStrength = 0.1;
}
```

FIXES=[391663042]

Co-authored-by: Powei Feng <powei@google.com>

---------

Co-authored-by: Powei Feng <powei@google.com>
2025-03-20 14:03:52 -07:00
Powei Feng de5d0e55af webgpu: enable webgpu build for test on linux (#8549) 2025-03-20 20:57:49 +00:00
Benjamin Doherty 6066e3a461 Release Filament 1.58.1 2025-03-19 16:17:13 -07:00
rafadevai ea0bbad636 vk: Refactor Vulkan android into its own class (#8538) 2025-03-19 20:41:44 +00:00
Eliza Velasquez 65861b85cf 1dlut: fix psychadelic lookup tables 2025-03-19 12:15:35 -07:00
Eliza Velasquez 1f169d7e75 1dlut: fix iOS build 2025-03-19 12:15:35 -07:00
Eliza Velasquez daa359717b 1dlut: mathias feedback 2025-03-19 12:15:35 -07:00
Eliza Velasquez 4fbfd1b8c1 Generate 1D LUTs for color grading when possible
This introduces two new methods to `ToneMapper`: `isOneDimensional()` and
`isLDR()`. `ColorGrading` references these values along with other parameters
passed to the builder to determine if we can get away with only generating a
one-dimensional LUT. Meanwhile, `PostProcessManager` takes care of setting the
new spec constants and uniforms for `colorGrading.mat` and
`colorGradingAsSubpass.mat`.
2025-03-19 12:15:35 -07:00
Syed Idris Shah 67f05c15d0 Fix WebGPU compilation error
WebGPU is broken because of 3abddc4584 change
2025-03-19 13:25:09 -04:00
Doris Wu 4db3cc521b Move includes outside fgviewer namespace (#8543) 2025-03-19 13:42:34 +08:00
alizahlalani 9e6cf3c876 Refactored external image handling in PlatformEGLAndroid (#8512) 2025-03-18 23:46:31 +00:00
Powei Feng b64548267e vk: disable transient texture for depth resolve (#8534)
Depth resolve is handled via a custom shader and therefore cannot
use the transient texture path.

This is fixes the black screen bug when MSAA is turned on and
when using the latest MoltenVK (1.2.11).
2025-03-18 17:51:59 +00:00
Randy Reyes 5c811844ff webgpu: fix spacing 2025-03-18 10:25:10 -07:00
Randy Reyes e6b18b4560 webgpu: enable unpacking WGSL code in filamat 2025-03-18 10:25:10 -07:00
Powei Feng 1571ea846b vk: minor swizzle code clean-up (#8535) 2025-03-18 17:09:55 +00:00
186 changed files with 10057 additions and 1074 deletions
+16 -10
View File
@@ -92,27 +92,33 @@ jobs:
test-renderdiff:
name: test-renderdiff
runs-on: ubuntu-22.04-4core
runs-on: macos-14-xlarge
steps:
- uses: actions/checkout@v4.1.6
- uses: ./.github/actions/ubuntu-apt-add-src
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install python prereqs
run: pip install mako setuptools pyyaml
- name: Run script
run: |
echo "Disabled renderdiff due to Mesa -> Currently planned outage: 2025-03-16 -> 2025-03-22"
# source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh
bash test/renderdiff/test.sh
- uses: actions/upload-artifact@v4
with:
name: presubmit-renderdiff-result
path: ./out/renderdiff_tests
validate-wgsl-pipeline:
name: validate-wgsl-pipeline
runs-on: ubuntu-22.04-4core
validate-wgsl-webgpu:
name: validate-wgsl-webgpu
runs-on: ubuntu-22.04-8core
steps:
- uses: actions/checkout@v4.1.6
- name: Run build script
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
- name: Run test
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
+12 -6
View File
@@ -139,14 +139,14 @@ else()
set(LINUX FALSE)
endif()
if (LINUX)
if (NOT FILAMENT_OSMESA_PATH STREQUAL "")
if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/)
message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}")
endif()
set(FILAMENT_SUPPORTS_OSMESA TRUE)
if (NOT FILAMENT_OSMESA_PATH STREQUAL "")
if (NOT EXISTS ${FILAMENT_OSMESA_PATH}/)
message(FATAL_ERROR "Cannot find specified OSMesa build directory: ${FILAMENT_OSMESA_PATH}")
endif()
set(FILAMENT_SUPPORTS_OSMESA TRUE)
endif()
if (LINUX)
if (FILAMENT_SUPPORTS_WAYLAND)
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
set(FILAMENT_SUPPORTS_X11 FALSE)
@@ -184,6 +184,12 @@ if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE)
set(IS_HOST_PLATFORM TRUE)
endif()
if (APPLE)
if (FILAMENT_SUPPORTS_OSMESA)
add_definitions(-DFILAMENT_SUPPORTS_OSMESA)
endif()
endif()
if (WIN32)
# Link statically against c/c++ lib to avoid missing redistriburable such as
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
+3
View File
@@ -7,3 +7,6 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.58.0'
implementation 'com.google.android.filament:filament-android:1.58.1'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.58.0'
pod 'Filament', '~> 1.58.1'
```
## Documentation
+4
View File
@@ -7,6 +7,10 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.58.2
- engine: Generate 1D instead of 3D LUTs for color grading whenever possible.
## v1.58.1
@@ -46,9 +46,8 @@ import static com.google.android.filament.Asserts.assertFloat4In;
*
* <h1>Performance</h1>
*
* Creating a new ColorGrading object may be more expensive than other Filament objects as a
* 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on
* the CPU.
* Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may
* need to be generated. The generation of this LUT, if necessary, may happen on the CPU.
*
* <h1>Ordering</h1>
*
@@ -160,6 +159,10 @@ public class ColorGrading {
* quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit
* LUT, and a ultra quality will use a 64x64x64 16 bit LUT.
*
* This setting has no effect if generating a 1D LUT.
*
* This overrides the values set by format() and dimensions().
*
* The default quality is {@link QualityLevel#MEDIUM}.
*
* @param qualityLevel The desired quality of the color grading process
@@ -175,6 +178,8 @@ public class ColorGrading {
* When color grading is implemented using a 3D LUT, this sets the texture format of
* of the LUT. This overrides the value set by quality().
*
* This setting has no effect if generating a 1D LUT.
*
* The default is INTEGER
*
* @param format The desired format of the 3D LUT.
@@ -190,6 +195,8 @@ public class ColorGrading {
* When color grading is implemented using a 3D LUT, this sets the dimension of the LUT.
* This overrides the value set by quality().
*
* This setting has no effect if generating a 1D LUT.
*
* The default is 32
*
* @param dim The desired dimension of the LUT. Between 16 and 64.
@@ -616,4 +623,3 @@ public class ColorGrading {
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
}
@@ -31,8 +31,6 @@ package com.google.android.filament;
* <li>DisplayRangeToneMapper</li>
* </ul>
* </ul>
*
* You can create custom tone mapping operators by subclassing ToneMapper.
*/
public class ToneMapper {
private final long mNativeObject;
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.58.0
VERSION_NAME=1.58.1
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+4 -1
View File
@@ -200,8 +200,9 @@ WEBGPU_ANDROID_GRADLE_OPTION=""
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
MATDBG_GRADLE_OPTION=""
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
FGVIEWER_GRADLE_OPTION=""
MATOPT_OPTION=""
MATOPT_GRADLE_OPTION=""
@@ -533,6 +534,7 @@ function build_android {
${VULKAN_ANDROID_GRADLE_OPTION} \
${WEBGPU_ANDROID_GRADLE_OPTION} \
${MATDBG_GRADLE_OPTION} \
${FGVIEWER_GRADLE_OPTION} \
${MATOPT_GRADLE_OPTION} \
:filament-android:assembleDebug \
:gltfio-android:assembleDebug \
@@ -584,6 +586,7 @@ function build_android {
${VULKAN_ANDROID_GRADLE_OPTION} \
${WEBGPU_ANDROID_GRADLE_OPTION} \
${MATDBG_GRADLE_OPTION} \
${FGVIEWER_GRADLE_OPTION} \
${MATOPT_GRADLE_OPTION} \
:filament-android:assembleRelease \
:gltfio-android:assembleRelease \
+1 -1
View File
@@ -31,7 +31,7 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
# For dawn
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
+23 -15
View File
@@ -13,7 +13,7 @@ This document is part of the [Filament project](https://github.com/google/filame
## Authors
- [Romain Guy](https://github.com/romainguy), [@romainguy](https://twitter.com/romainguy)
- [Mathias Agopian](https://github.com/pixelflinger), [@darthmoosious](https://twitter.com/darthmoosious)
- [Mathias Agopian](https://github.com/pixelflinger), [@pixelflinger](https://bsky.app/profile/pixelflinger.bsky.social)
# Overview
@@ -78,26 +78,27 @@ in table [standardProperties].
Property | Definition
-----------------------:|:---------------------
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
**roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
**metallic** | Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
**reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
**sheenColor** | Strength of the sheen layer
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
**clearCoat** | Strength of the clear coat layer
**clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
**anisotropy** | Amount of anisotropy in either the tangent or bitangent direction
**anisotropyDirection** | Local surface direction in tangent space
**ambientOcclusion** | Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
**clearCoatNormal** | A detail normal used to perturb the clear coat layer using _bump mapping_ (_normal mapping_)
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
**absorption** | Absorption factor for refractive objects
**microThickness** | Thickness of the thin layer of refractive objects
**thickness** | Thickness of the solid volume of refractive objects
**sheenColor** | Strength of the sheen layer
**sheenRoughness** | Perceived smoothness or roughness of the sheen layer
**emissive** | Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
**normal** | A detail normal used to perturb the surface using _bump mapping_ (_normal mapping_)
**postLightingColor** | Additional color that can be blended with the result of the lighting computations. See `postLightingBlending`
**absorption** | Absorption factor for refractive objects
**transmission** | Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
**ior** | Index of refraction, either for refractive objects or as an alternative to reflectance
**microThickness** | Thickness of the thin layer of refractive objects
**bentNormal** | A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
**shadowStrength** | Strength factor between 0 and 1 for all shadows received by this material
[Table [standardProperties]: Properties of the standard model]
The type and range of each property is described in table [standardPropertiesTypes].
@@ -1272,6 +1273,9 @@ Description
when selecting any shading model that is not `unlit`. See the shader sections of this document
for more information on how to access these attributes from the shaders.
!!! Note: Interaction with custom variables
When the `color` attribute is specified, only four custom variables are available instead of five.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
parameters : [
@@ -1302,7 +1306,7 @@ Type
: array of `string`
Value
: Up to 4 strings, each must be a valid GLSL identifier.
: Up to 5 strings, each must be a valid GLSL identifier.
Description
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
@@ -1318,6 +1322,10 @@ Description
particular if `default` is specified the default precision is used is the fragment shader
(`mediump`) and in the vertex shader (`highp`).
!!! Warning: Interaction with required attributes
If the `color` attribute is specified in the `required` list, then only four variables can be used
instead of five.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
name : Skybox,
+18 -9
View File
@@ -108,8 +108,12 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3)
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
elseif (APPLE)
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
if (FILAMENT_SUPPORTS_OSMESA)
list(APPEND SRCS src/opengl/platforms/PlatformOSMesa.cpp)
else()
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
endif()
elseif (WEBGL)
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
elseif (LINUX)
@@ -173,10 +177,12 @@ endif()
if (FILAMENT_SUPPORTS_VULKAN)
list(APPEND SRCS
include/backend/platforms/VulkanPlatform.h
src/vulkan/caching/VulkanDescriptorSetManager.cpp
src/vulkan/caching/VulkanDescriptorSetManager.h
src/vulkan/caching/VulkanPipelineLayoutCache.cpp
src/vulkan/caching/VulkanPipelineLayoutCache.h
src/vulkan/VulkanDescriptorSetCache.cpp
src/vulkan/VulkanDescriptorSetCache.h
src/vulkan/VulkanDescriptorSetLayoutCache.cpp
src/vulkan/VulkanDescriptorSetLayoutCache.h
src/vulkan/VulkanPipelineLayoutCache.cpp
src/vulkan/VulkanPipelineLayoutCache.h
src/vulkan/memory/ResourceManager.cpp
src/vulkan/memory/ResourceManager.h
src/vulkan/memory/ResourcePointer.h
@@ -416,9 +422,12 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS
-Wl,--exclude-libs,bluegl
)
if (LINUX AND FILAMENT_SUPPORTS_OSMESA)
set(OSMESA_COMPILE_FLAGS
-I${FILAMENT_OSMESA_PATH}/include/GL)
if (FILAMENT_SUPPORTS_OSMESA)
if (LINUX)
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL)
elseif (APPLE)
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include)
endif()
endif()
if (MSVC)
+10 -6
View File
@@ -256,16 +256,18 @@ struct DescriptorSetLayoutBinding {
DescriptorFlags flags = DescriptorFlags::NONE;
uint16_t count = 0;
uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
// TODO: uncomment when needed. Note that this class is used as hash key. We need to ensure
// no uninitialized padding bytes.
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
friend inline bool operator==(
DescriptorSetLayoutBinding const& lhs,
friend inline bool operator==(DescriptorSetLayoutBinding const& lhs,
DescriptorSetLayoutBinding const& rhs) noexcept {
return lhs.type == rhs.type &&
lhs.flags == rhs.flags &&
lhs.count == rhs.count &&
lhs.stageFlags == rhs.stageFlags &&
lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
lhs.stageFlags == rhs.stageFlags;
// lhs.stageFlags == rhs.stageFlags &&
// lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
}
};
@@ -1138,7 +1140,9 @@ static_assert(sizeof(ExternalSamplerDatum) == 12);
struct DescriptorSetLayout {
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
// TODO: uncomment when needed
// utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
};
//! blending equation function
@@ -33,7 +33,7 @@ public:
PlatformCocoaGL();
~PlatformCocoaGL() noexcept override;
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
protected:
// --------------------------------------------------------------------------------------------
@@ -32,7 +32,7 @@ public:
PlatformCocoaTouchGL();
~PlatformCocoaTouchGL() noexcept override;
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
// --------------------------------------------------------------------------------------------
// Platform Interface
@@ -50,7 +50,7 @@ public:
/**
* Creates an ExternalImage from a EGLImageKHR
*/
ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept;
ExternalImageHandle UTILS_PUBLIC createExternalImage(EGLImageKHR eglImage) noexcept;
protected:
// --------------------------------------------------------------------------------------------
@@ -23,6 +23,7 @@
#include <backend/platforms/PlatformEGL.h>
#include <utils/android/PerformanceHintManager.h>
#include <utils/compiler.h>
#include <chrono>
@@ -43,8 +44,21 @@ public:
PlatformEGLAndroid() noexcept;
~PlatformEGLAndroid() noexcept override;
protected:
/**
* Creates an ExternalImage from a EGLImageKHR
*/
ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept;
struct UTILS_PUBLIC ExternalImageDescAndroid {
uint32_t width; // Texture width
uint32_t height; // Texture height
TextureFormat format;// Texture format
TextureUsage usage; // Texture usage flags
};
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(ExternalImageHandle externalImage) noexcept;
protected:
// --------------------------------------------------------------------------------------------
// Platform Interface
@@ -57,11 +71,6 @@ protected:
Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
/**
* Creates an ExternalImage from a EGLImageKHR
*/
ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept;
// --------------------------------------------------------------------------------------------
// OpenGLPlatform Interface
@@ -95,15 +104,26 @@ protected:
*/
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
struct ExternalImageEGLAndroid : public ExternalImageEGL {
AHardwareBuffer* aHardwareBuffer = nullptr;
uint32_t width; // Texture width
uint32_t height; // Texture height
TextureFormat format;// Texture format
TextureUsage usage; // Texture usage flags
bool sRGB = false;
protected:
~ExternalImageEGLAndroid() override;
};
bool setExternalImage(ExternalImageHandleRef externalImage,
ExternalTexture* texture) noexcept override;
bool setImage(ExternalImageEGLAndroid const* eglExternalImage,
ExternalTexture* texture) noexcept;
protected:
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
@@ -21,7 +21,12 @@
#include "bluegl/BlueGL.h"
#if defined(__linux__)
#include <osmesa.h>
#elif defined(__APPLE__)
#undef GLAPI
#include <GL/osmesa.h>
#endif
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
@@ -368,8 +368,16 @@ public:
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
VkImageViewType viewType, VkComponentMapping swizzle);
protected:
virtual ExtensionSet getSwapchainInstanceExtensions() const;
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept;
private:
static ExtensionSet getSwapchainInstanceExtensions();
// Platform dependent helper methods
static ExtensionSet getSwapchainInstanceExtensionsImpl();
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
VkDevice device);
@@ -386,8 +394,7 @@ private:
VkComponentMapping swizzle);
// Platform dependent helper methods
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
uint64_t flags) noexcept;
friend struct VulkanPlatformPrivate;
@@ -17,27 +17,55 @@
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
#include <backend/Platform.h>
#include <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatform.h>
#include <android/hardware_buffer.h>
namespace filament::backend::fvkandroid {
namespace filament::backend {
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
AHardwareBuffer* aHardwareBuffer = nullptr;
bool sRGB = false;
unsigned int width; // Texture width
unsigned int height; // Texture height
TextureFormat format; // Texture format
TextureUsage usage; // Texture usage flags
class VulkanPlatformAndroid : public VulkanPlatform {
public:
Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
bool sRGB) noexcept;
struct UTILS_PUBLIC ExternalImageDescAndroid {
uint32_t width; // Texture width
uint32_t height; // Texture height
TextureFormat format;// Texture format
TextureUsage usage; // Texture usage flags
};
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
ExternalImageHandleRef externalImage) const noexcept;
protected:
~ExternalImageVulkanAndroid() override;
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
AHardwareBuffer* aHardwareBuffer = nullptr;
bool sRGB = false;
unsigned int width; // Texture width
unsigned int height; // Texture height
TextureFormat format;// Texture format
TextureUsage usage; // Texture usage flags
protected:
~ExternalImageVulkanAndroid() override;
};
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
using ImageData = VulkanPlatform::ImageData;
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
VkImageUsageFlags usage);
virtual ExtensionSet getSwapchainInstanceExtensions() const;
using SurfaceBundle = VulkanPlatform::SurfaceBundle;
virtual SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
uint64_t flags) const noexcept;
};
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
bool sRGB) noexcept;
}// namespace filament::backend
} // namespace filament::backend::fvkandroid
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
+25 -7
View File
@@ -19,6 +19,11 @@
#include <utils/Systrace.h>
#include <utils/debug.h>
// We need to keep this up top for the linux (X11) name collisions.
#if defined(FILAMENT_SUPPORTS_WEBGPU)
#include "backend/platforms/WebGPUPlatform.h"
#endif
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
@@ -30,7 +35,11 @@
#endif
#elif defined(__APPLE__)
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
#include <backend/platforms/PlatformCocoaGL.h>
#if defined(FILAMENT_SUPPORTS_OSMESA)
#include <backend/platforms/PlatformOSMesa.h>
#else
#include <backend/platforms/PlatformCocoaGL.h>
#endif
#endif
#elif defined(__linux__)
#if defined(FILAMENT_SUPPORTS_X11)
@@ -55,7 +64,11 @@
#endif
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
#include "backend/platforms/VulkanPlatform.h"
#if defined(__ANDROID__)
#include "backend/platforms/VulkanPlatformAndroid.h"
#else
#include "backend/platforms/VulkanPlatform.h"
#endif
#endif
#if defined (FILAMENT_SUPPORTS_METAL)
@@ -65,9 +78,6 @@ filament::backend::Platform* createDefaultMetalPlatform();
#endif
#include "noop/PlatformNoop.h"
#if defined(FILAMENT_SUPPORTS_WEBGPU)
#include "backend/platforms/WebGPUPlatform.h"
#endif
namespace filament::backend {
@@ -104,7 +114,11 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
}
if (*backend == Backend::VULKAN) {
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
return new VulkanPlatform();
#if defined(__ANDROID__)
return new VulkanPlatformAndroid();
#else
return new VulkanPlatform();
#endif
#else
return nullptr;
#endif
@@ -132,7 +146,11 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
#elif defined(FILAMENT_IOS)
return new PlatformCocoaTouchGL();
#elif defined(__APPLE__)
return new PlatformCocoaGL();
#if defined(FILAMENT_SUPPORTS_OSMESA)
return new PlatformOSMesa();
#else
return new PlatformCocoaGL();
#endif
#elif defined(__linux__)
#if defined(FILAMENT_SUPPORTS_X11)
return new PlatformGLX();
+1 -1
View File
@@ -241,7 +241,7 @@ size_t NoopDriver::getMaxUniformBufferSize() {
}
size_t NoopDriver::getMaxTextureSize(SamplerType target) {
return 2048u;
return 4096u;
}
size_t NoopDriver::getMaxArrayTextureLayers() {
+1 -1
View File
@@ -20,7 +20,7 @@
namespace filament::backend {
Driver* PlatformNoop::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
return NoopDriver::create();
}
+6 -6
View File
@@ -148,8 +148,8 @@ using namespace utils;
namespace filament::backend {
Driver* OpenGLDriverFactory::create(
OpenGLPlatform* const platform,
void* const sharedGLContext,
OpenGLPlatform* platform,
void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept {
return OpenGLDriver::create(platform, sharedGLContext, driverConfig);
}
@@ -159,10 +159,10 @@ using namespace GLUtils;
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
void* /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
assert_invariant(platform);
OpenGLPlatform* const ec = platform;
OpenGLPlatform* ec = platform;
#if 0
// this is useful for development, but too verbose even for debug builds
@@ -230,7 +230,7 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig validConfig{ driverConfig };
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
OpenGLDriver* driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
return driver;
}
@@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept {
delete pImpl;
}
Driver* PlatformCocoaTouchGL::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
@@ -19,6 +19,7 @@
#include <backend/platforms/PlatformEGL.h>
#include <backend/platforms/PlatformEGLAndroid.h>
#include <private/backend/BackendUtilsAndroid.h>
#include <private/backend/VirtualMachineEnv.h>
#include "opengl/GLUtils.h"
@@ -34,6 +35,8 @@
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -231,26 +234,133 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
return driver;
}
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default;
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() {
if (__builtin_available(android 26, *)) {
if (aHardwareBuffer) {
AHardwareBuffer_release(aHardwareBuffer);
}
}
}
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept {
auto* const p = new(std::nothrow) ExternalImageEGLAndroid;
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
p->sRGB = sRGB;
return ExternalImageHandle{ p };
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer,
bool sRGB) noexcept {
if (__builtin_available(android 26, *)) {
auto* const p = new (std::nothrow) ExternalImageEGLAndroid;
auto hardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
AHardwareBuffer_acquire(hardwareBuffer);
p->aHardwareBuffer = hardwareBuffer;
p->sRGB = sRGB;
AHardwareBuffer_Desc hardwareBufferDescription = {};
AHardwareBuffer_describe(hardwareBuffer, &hardwareBufferDescription);
p->height = hardwareBufferDescription.height;
p->width = hardwareBufferDescription.width;
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
return ExternalImageHandle{ p };
}
return Platform::ExternalImageHandle{};
}
PlatformEGLAndroid::ExternalImageDescAndroid PlatformEGLAndroid::getExternalImageDesc(
ExternalImageHandle externalImage) noexcept {
auto const* const eglExternalImage =
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
ExternalImageDescAndroid metadata = {};
if (!eglExternalImage) {
return metadata;
}
metadata.height = eglExternalImage->height;
metadata.width = eglExternalImage->width;
metadata.format = eglExternalImage->format;
metadata.usage = eglExternalImage->usage;
return metadata;
}
bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage,
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
auto const* const eglExternalImage = static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
auto const* const eglExternalImage =
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
if (eglExternalImage->aHardwareBuffer) {
// TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer
return true;
return PlatformEGLAndroid::setImage(eglExternalImage, texture);
}
// not a AHardwareBuffer, fallback to the inherited version
return PlatformEGL::setExternalImage(externalImage, texture);
}
OpenGLPlatform::ExternalTexture* PlatformEGLAndroid::createExternalImageTexture() noexcept {
ExternalTexture* outTexture = new (std::nothrow) ExternalTexture{};
glGenTextures(1, &outTexture->id);
return outTexture;
}
void PlatformEGLAndroid::destroyExternalImageTexture(ExternalTexture* texture) noexcept {
glDeleteTextures(1, &texture->id);
delete texture;
}
bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImage,
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
AHardwareBuffer* hardwareBuffer = eglExternalImage->aHardwareBuffer;
// Get the EGL client buffer from AHardwareBuffer
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
EGLint imageAttrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE, EGL_NONE, // Reserve space
EGL_NONE, EGL_NONE, // Reserve space
EGL_NONE // Ensure the list always ends with EGL_NONE
};
int attrIndex = 2;
if (eglExternalImage->sRGB) {
imageAttrs[attrIndex++] = EGL_GL_COLORSPACE;
imageAttrs[attrIndex++] = EGL_GL_COLORSPACE_SRGB;
}
if (static_cast<bool>(eglExternalImage->usage & TextureUsage::PROTECTED)) {
imageAttrs[attrIndex++] = EGL_PROTECTED_CONTENT_EXT;
imageAttrs[attrIndex++] = EGL_TRUE;
}
// Create an EGLImage from the client buffer
EGLImageKHR eglImage = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
if (eglImage == EGL_NO_IMAGE_KHR) {
// Handle error
slog.e << "Failed to create EGL image" << io::endl;
glDeleteTextures(1, &texture->id);
return false;
}
// Create and bind the OpenGL texture
GLint prevActiveTexture, prevTexture;
glGetIntegerv(GL_ACTIVE_TEXTURE, &prevActiveTexture);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->id);
GLenum error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
slog.e << "Error after glBindTexture: " << error << io::endl;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
glBindTexture(GL_TEXTURE_2D, prevTexture);
return false;
}
glEGLImageTargetTexture2DOES(texture->target, static_cast<GLeglImageOES>(eglImage));
error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
slog.e << "Error after glEGLImageTargetTexture2DOES: " << error << io::endl;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
glBindTexture(GL_TEXTURE_2D, prevTexture);
return false;
}
glActiveTexture(prevActiveTexture);
glBindTexture(GL_TEXTURE_2D, prevTexture);
return true;
}
void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept {
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
if (currentDrawSurface != EGL_NO_SURFACE) {
@@ -128,7 +128,7 @@ namespace filament::backend {
using namespace backend;
Driver* PlatformGLX::createDriver(void* const sharedGLContext,
Driver* PlatformGLX::createDriver(void* sharedGLContext,
const DriverConfig& driverConfig) noexcept {
loadLibraries();
// Get the display device
@@ -22,9 +22,11 @@
#include <dlfcn.h>
#include <memory>
#if defined(__linux__)
// This is to ensure that linking during compilation will not fail even if
// OSMesaGetProcAddress is not linked.
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
#endif
namespace filament::backend {
@@ -48,20 +50,27 @@ struct OSMesaSwapchain {
struct OSMesaAPI {
private:
using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext);
using CreateContextAttribsFunc = OSMesaContext (*)(const int *, OSMesaContext);
using DestroyContextFunc = GLboolean (*)(OSMesaContext);
using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type,
GLsizei width, GLsizei height);
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
public:
CreateContextFunc fOSMesaCreateContext;
CreateContextAttribsFunc fOSMesaCreateContextAttribs;
DestroyContextFunc fOSMesaDestroyContext;
MakeCurrentFunc fOSMesaMakeCurrent;
GetProcAddressFunc fOSMesaGetProcAddress;
OSMesaAPI() {
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
static constexpr char const* libraryNames[] = {
#if defined(__linux__)
"libOSMesa.so",
"libosmesa.so",
#elif defined(__APPLE__)
"libOSMesa.dylib",
#endif
};
for (char const* libName: libraryNames) {
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
if (mLib) {
@@ -71,22 +80,24 @@ public:
if (mLib) {
// Loading from a libosmesa.os
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
} else {
}
#if defined(__linux__)
else {
// Filament is built into a .so
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
}
if (!fOSMesaGetProcAddress) {
// Statically linking osmesa
fOSMesaGetProcAddress = OSMesaGetProcAddress;
}
#endif // __linux__
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
<< "Unable to link against libOSMesa to create a software GL context";
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
fOSMesaDestroyContext =
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
fOSMesaCreateContextAttribs =
(CreateContextAttribsFunc) fOSMesaGetProcAddress("OSMesaCreateContextAttribs");
fOSMesaDestroyContext = (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
}
@@ -101,14 +112,24 @@ private:
}// anonymous namespace
Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
Driver* PlatformOSMesa::createDriver(void* sharedGLContext,
const DriverConfig& driverConfig) noexcept {
OSMesaAPI* api = new OSMesaAPI();
mOsMesaApi = api;
static constexpr int attribs[] = {
OSMESA_FORMAT, GL_RGBA,
OSMESA_DEPTH_BITS, 24,
OSMESA_STENCIL_BITS, 8,
OSMESA_ACCUM_BITS, 0,
OSMESA_PROFILE, OSMESA_CORE_PROFILE,
0,
};
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
<< "shared GL context is not supported with PlatformOSMesa";
mContext = api->fOSMesaCreateContext(GL_RGBA, NULL);
mContext = api->fOSMesaCreateContextAttribs(attribs, NULL);
// We need to do a no-op makecurrent here so that the context will be in a correct state before
// any GL calls.
@@ -75,7 +75,7 @@ struct WGLSwapChain {
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
Driver* PlatformWGL::createDriver(void* const sharedGLContext,
Driver* PlatformWGL::createDriver(void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept {
int result = 0;
int pixelFormat = 0;
@@ -20,7 +20,7 @@ namespace filament::backend {
using namespace backend;
Driver* PlatformWebGL::createDriver(void* const sharedGLContext,
Driver* PlatformWebGL::createDriver(void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept {
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
}
@@ -14,35 +14,25 @@
* limitations under the License.
*/
#include "VulkanDescriptorSetManager.h"
#include "VulkanDescriptorSetCache.h"
#include "vulkan/VulkanCommands.h"
#include "vulkan/VulkanHandles.h"
#include "vulkan/VulkanConstants.h"
#include "VulkanCommands.h"
#include "VulkanHandles.h"
#include "VulkanConstants.h"
#include <utils/FixedCapacityVector.h>
#include <utils/Panic.h>
#include <math.h>
#include <algorithm>
#include <memory>
#include <type_traits>
#include <vector>
namespace filament::backend {
namespace {
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
using DescriptorCount = VulkanDescriptorSetLayout::Count;
using DescriptorSetLayoutArray = VulkanDescriptorSetManager::DescriptorSetLayoutArray;
using BitmaskGroupHashFn = utils::hash::MurmurHashFn<BitmaskGroup>;
struct BitmaskGroupEqual {
bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const {
return k1 == k2;
}
};
using DescriptorSetLayoutArray = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
// We create a pool for each layout as defined by the number of descriptors of each type. For
// example, a layout of
@@ -199,72 +189,12 @@ struct Equal {
}
};
template<typename Bitmask>
uint32_t createBindings(VkDescriptorSetLayoutBinding* toBind, uint32_t count, VkDescriptorType type,
Bitmask const& mask) {
Bitmask alreadySeen;
mask.forEachSetBit([&](size_t index) {
VkShaderStageFlags stages = 0;
uint32_t binding = 0;
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
binding = (uint32_t) index;
stages |= VK_SHADER_STAGE_VERTEX_BIT;
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
if (mask.test(fragIndex)) {
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
alreadySeen.set(fragIndex);
}
} else if (!alreadySeen.test(index)) {
// We are in fragment stage bits
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
}
if (stages) {
toBind[count++] = {
.binding = binding,
.descriptorType = type,
.descriptorCount = 1,
.stageFlags = stages,
};
}
});
return count;
}
inline VkDescriptorSetLayout createLayout(VkDevice device, BitmaskGroup const& bitmaskGroup) {
// Note that the following *needs* to be static so that VkDescriptorSetLayoutCreateInfo will not
// refer to stack memory.
VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS];
uint32_t count = 0;
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
bitmaskGroup.dynamicUbo);
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmaskGroup.ubo);
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
bitmaskGroup.sampler);
count = createBindings(toBind, count, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
bitmaskGroup.inputAttachment);
assert_invariant(count != 0 && "Need at least one binding for descriptor set layout.");
VkDescriptorSetLayoutCreateInfo dlinfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.bindingCount = count,
.pBindings = toBind,
};
VkDescriptorSetLayout layout;
vkCreateDescriptorSetLayout(device, &dlinfo, VKALLOC, &layout);
return layout;
}
} // anonymous namespace
// This is an ever-expanding pool of sets where it
// 1. Keeps a list of smaller pools of different layout-dimensions.
// 2. Will add a pool if existing pool are not compatible with the requested layout o runs out.
class VulkanDescriptorSetManager::DescriptorInfinitePool {
class VulkanDescriptorSetCache::DescriptorInfinitePool {
private:
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
@@ -319,61 +249,34 @@ private:
std::vector<std::unique_ptr<DescriptorPool>> mPools;
};
class VulkanDescriptorSetManager::DescriptorSetLayoutManager {
public:
DescriptorSetLayoutManager(VkDevice device)
: mDevice(device) {}
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks) {
if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) {
return itr->second;
}
auto vklayout = createLayout(mDevice, bitmasks);
mVkLayouts[bitmasks] = vklayout;
return vklayout;
}
~DescriptorSetLayoutManager() {
for (auto& itr: mVkLayouts) {
vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC);
}
}
private:
VkDevice mDevice;
tsl::robin_map<BitmaskGroup, VkDescriptorSetLayout, BitmaskGroupHashFn, BitmaskGroupEqual>
mVkLayouts;
};
VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device,
VulkanDescriptorSetCache::VulkanDescriptorSetCache(VkDevice device,
fvkmemory::ResourceManager* resourceManager)
: mDevice(device),
mResourceManager(resourceManager),
mLayoutManager(std::make_unique<DescriptorSetLayoutManager>(device)),
mDescriptorPool(std::make_unique<DescriptorInfinitePool>(device)) {}
VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default;
VulkanDescriptorSetCache::~VulkanDescriptorSetCache() = default;
void VulkanDescriptorSetManager::terminate() noexcept{
mLayoutManager.reset();
void VulkanDescriptorSetCache::terminate() noexcept{
mDescriptorPool.reset();
clearHistory();
}
// bind() is not really binding the set but just stashing until we have all the info
// (pipelinelayout).
void VulkanDescriptorSetManager::bind(uint8_t setIndex,
void VulkanDescriptorSetCache::bind(uint8_t setIndex,
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
backend::DescriptorSetOffsetArray&& offsets) {
set->setOffsets(std::move(offsets));
mStashedSets[setIndex] = set;
}
void VulkanDescriptorSetManager::unbind(uint8_t setIndex) {
void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
mStashedSets[setIndex] = {};
}
void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands,
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
// actual set of sets that *needs* to be bound.
@@ -412,7 +315,7 @@ void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands,
};
}
void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
VkDeviceSize offset, VkDeviceSize size) noexcept {
VkDescriptorBufferInfo const info = {
@@ -438,7 +341,7 @@ void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr<VulkanDesc
set->acquire(bufferObject);
}
void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
VkSampler sampler) noexcept {
VkDescriptorImageInfo info{
@@ -470,13 +373,13 @@ void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr<VulkanDes
set->acquire(texture);
}
void VulkanDescriptorSetManager::updateInputAttachment(
void VulkanDescriptorSetCache::updateInputAttachment(
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
VulkanAttachment const& attachment) noexcept {
// TOOD: fill-in this region
// TOOD: fill this in.
}
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetManager::createSet(
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
auto const vkSet = mDescriptorPool->obtainSet(layout);
auto const& count = layout->count;
@@ -492,12 +395,7 @@ fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetManager::createS
});
}
void VulkanDescriptorSetManager::initVkLayout(
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
layout->setVkLayout(mLayoutManager->getVkLayout(layout->bitmask));
}
void VulkanDescriptorSetManager::clearHistory() {
void VulkanDescriptorSetCache::clearHistory() {
mStashedSets = {};
}
@@ -14,10 +14,10 @@
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
#include "vulkan/VulkanHandles.h"
#include "VulkanHandles.h"
#include "vulkan/memory/ResourcePointer.h"
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
@@ -34,20 +34,16 @@
namespace filament::backend {
// [GDSR]: Great-Descriptor-Set-Refactor: As of 03/20/24, the Filament frontend is planning to
// introduce descriptor set. This PR will arrive before that change is complete. As such, some of
// the methods introduced here will be obsolete, and certain logic will be generalized.
// Abstraction over the pool and the layout cache.
class VulkanDescriptorSetManager {
// Abstraction over the descriptor set pool.
class VulkanDescriptorSetCache {
public:
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager);
~VulkanDescriptorSetManager();
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
~VulkanDescriptorSetCache();
void terminate() noexcept;
@@ -72,12 +68,9 @@ public:
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
void initVkLayout(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
void clearHistory();
private:
class DescriptorSetLayoutManager;
class DescriptorInfinitePool;
using DescriptorSetArray =
@@ -85,7 +78,6 @@ private:
VkDevice mDevice;
fvkmemory::ResourceManager* mResourceManager;
std::unique_ptr<DescriptorSetLayoutManager> mLayoutManager;
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
DescriptorSetArray mStashedSets = {};
@@ -99,4 +91,4 @@ private:
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
@@ -0,0 +1,110 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VulkanDescriptorSetLayoutCache.h"
#include "VulkanHandles.h"
namespace filament::backend {
namespace {
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
template<typename Bitmask>
uint32_t appendBindings(VkDescriptorSetLayoutBinding* toBind, VkDescriptorType type,
Bitmask const& mask) {
uint32_t count = 0;
Bitmask alreadySeen;
mask.forEachSetBit([&](size_t index) {
VkShaderStageFlags stages = 0;
uint32_t binding = 0;
if (index < fvkutils::getFragmentStageShift<Bitmask>()) {
binding = (uint32_t) index;
stages |= VK_SHADER_STAGE_VERTEX_BIT;
auto fragIndex = index + fvkutils::getFragmentStageShift<Bitmask>();
if (mask.test(fragIndex)) {
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
alreadySeen.set(fragIndex);
}
} else if (!alreadySeen.test(index)) {
// We are in fragment stage bits
binding = (uint32_t) (index - fvkutils::getFragmentStageShift<Bitmask>());
stages |= VK_SHADER_STAGE_FRAGMENT_BIT;
}
if (stages) {
toBind[count++] = {
.binding = binding,
.descriptorType = type,
.descriptorCount = 1,
.stageFlags = stages,
};
}
});
return count;
}
} // anonymous namespace
VulkanDescriptorSetLayoutCache::VulkanDescriptorSetLayoutCache(VkDevice device,
fvkmemory::ResourceManager* resourceManager)
: mDevice(device),
mResourceManager(resourceManager) {}
VulkanDescriptorSetLayoutCache::~VulkanDescriptorSetLayoutCache() = default;
void VulkanDescriptorSetLayoutCache::terminate() noexcept {
for (auto& itr: mVkLayouts) {
vkDestroyDescriptorSetLayout(mDevice, itr.second, VKALLOC);
}
}
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> VulkanDescriptorSetLayoutCache::createLayout(
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info) {
auto layout = fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::make(mResourceManager, handle,
info);
VkDescriptorSetLayout vklayout = VK_NULL_HANDLE;
auto const& bitmasks = layout->bitmask;
if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) {
vklayout = itr->second;
} else {
VkDescriptorSetLayoutBinding toBind[VulkanDescriptorSetLayout::MAX_BINDINGS];
uint32_t count = 0;
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
bitmasks.dynamicUbo);
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bitmasks.ubo);
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
bitmasks.sampler);
count += appendBindings(&toBind[count], VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
bitmasks.inputAttachment);
assert_invariant(count != 0 && "Need at least one binding for descriptor set layout.");
VkDescriptorSetLayoutCreateInfo dlinfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.bindingCount = count,
.pBindings = toBind,
};
vkCreateDescriptorSetLayout(mDevice, &dlinfo, VKALLOC, &vklayout);
mVkLayouts[bitmasks] = vklayout;
}
layout->setVkLayout(vklayout);
return layout;
}
} // namespace filament::backend
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
#include "VulkanHandles.h"
#include "vulkan/memory/ResourcePointer.h"
#include <backend/DriverEnums.h>
#include <backend/Program.h>
#include <backend/TargetBufferInfo.h>
#include <utils/bitset.h>
#include <bluevk/BlueVK.h>
#include <tsl/robin_map.h>
#include <memory>
namespace filament::backend {
class VulkanDescriptorSetLayoutCache {
public:
VulkanDescriptorSetLayoutCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
~VulkanDescriptorSetLayoutCache();
void terminate() noexcept;
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> createLayout(
Handle<HwDescriptorSetLayout> handle, backend::DescriptorSetLayout&& info);
private:
VkDevice mDevice;
fvkmemory::ResourceManager* mResourceManager;
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
using BitmaskGroupHashFn = utils::hash::MurmurHashFn<BitmaskGroup>;
struct BitmaskGroupEqual {
bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const { return k1 == k2; }
};
tsl::robin_map<BitmaskGroup, VkDescriptorSetLayout, BitmaskGroupHashFn, BitmaskGroupEqual>
mVkLayouts;
};
} // namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETLAYOUTCACHE_H
+15 -18
View File
@@ -17,7 +17,6 @@
#include "VulkanDriver.h"
#include "CommandStreamDispatcher.h"
#include "DataReshaper.h"
#include "SystraceProfile.h"
#include "VulkanAsyncHandles.h"
#include "VulkanBuffer.h"
@@ -35,7 +34,6 @@
#include <backend/platforms/VulkanPlatform.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Panic.h>
#ifndef NDEBUG
@@ -44,8 +42,6 @@
using namespace bluevk;
using utils::FixedCapacityVector;
#if defined(__clang__)
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
// to a stack-allocated variable.
@@ -219,7 +215,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mSamplerCache(mPlatform->getDevice()),
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
mReadPixels(mPlatform->getDevice()),
mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager),
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
mQueryManager(mPlatform->getDevice()),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
mStereoscopicType(driverConfig.stereoscopicType) {
@@ -329,7 +326,8 @@ void VulkanDriver::terminate() {
mPipelineCache.terminate();
mFramebufferCache.reset();
mSamplerCache.terminate();
mDescriptorSetManager.terminate();
mDescriptorSetLayoutCache.terminate();
mDescriptorSetCache.terminate();
mPipelineLayoutCache.terminate();
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
@@ -365,7 +363,7 @@ void VulkanDriver::collectGarbage() {
FVK_SYSTRACE_SCOPE();
// Command buffers need to be submitted and completed before other resources can be gc'd.
mCommands.gc();
mDescriptorSetManager.clearHistory();
mDescriptorSetCache.clearHistory();
mStagePool.gc();
mFramebufferCache.gc();
mPipelineCache.gc();
@@ -408,7 +406,7 @@ void VulkanDriver::updateDescriptorSetBuffer(
FVK_SYSTRACE_SCOPE();
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
auto buffer = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
mDescriptorSetManager.updateBuffer(set, binding, buffer, offset, size);
mDescriptorSetCache.updateBuffer(set, binding, buffer, offset, size);
}
void VulkanDriver::updateDescriptorSetTexture(
@@ -421,7 +419,7 @@ void VulkanDriver::updateDescriptorSetTexture(
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
VkSampler const vksampler = mSamplerCache.getSampler(params);
mDescriptorSetManager.updateSampler(set, binding, texture, vksampler);
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
}
void VulkanDriver::flush(int) {
@@ -778,8 +776,7 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
backend::DescriptorSetLayout&& info) {
auto layout = resource_ptr<VulkanDescriptorSetLayout>::make(&mResourceManager, dslh, info);
mDescriptorSetManager.initVkLayout(layout);
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
layout.inc();
}
@@ -788,7 +785,7 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
FVK_SYSTRACE_SCOPE();
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
auto set = mDescriptorSetManager.createSet(dsh, layout);
auto set = mDescriptorSetCache.createSet(dsh, layout);
set.inc();
}
@@ -1060,7 +1057,7 @@ bool VulkanDriver::isDepthStencilBlitSupported(TextureFormat format) {
formats.end();
}
bool VulkanDriver::isProtectedTexturesSupported() { return false; }
bool VulkanDriver::isProtectedTexturesSupported() { return isProtectedContentSupported(); }
bool VulkanDriver::isDepthClampSupported() {
return mContext.isDepthClampSupported();
@@ -1149,7 +1146,7 @@ size_t VulkanDriver::getMaxUniformBufferSize() {
size_t VulkanDriver::getMaxTextureSize(SamplerType) {
// TODO: return the actual size instead of hardcoded value
return 2048;
return 4096;
}
size_t VulkanDriver::getMaxArrayTextureLayers() {
@@ -1493,7 +1490,7 @@ void VulkanDriver::nextSubpass(int) {
if (mCurrentRenderPass.params.subpassMask & 0x1) {
VulkanAttachment& subpassInput = renderTarget->getColor0();
mDescriptorSetManager.updateInputAttachment({}, subpassInput);
mDescriptorSetCache.updateInputAttachment({}, subpassInput);
}
}
@@ -1820,9 +1817,9 @@ void VulkanDriver::bindDescriptorSet(
backend::DescriptorSetOffsetArray&& offsets) {
if (dsh) {
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
mDescriptorSetManager.bind(setIndex, set, std::move(offsets));
mDescriptorSetCache.bind(setIndex, set, std::move(offsets));
} else {
mDescriptorSetManager.unbind(setIndex);
mDescriptorSetCache.unbind(setIndex);
}
}
@@ -1830,7 +1827,7 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
FVK_SYSTRACE_SCOPE();
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer,
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
mBoundPipeline.pipelineLayout,
mBoundPipeline.descriptorSetMask);
+5 -3
View File
@@ -27,8 +27,9 @@
#include "VulkanSamplerCache.h"
#include "VulkanStagePool.h"
#include "VulkanQueryManager.h"
#include "vulkan/caching/VulkanDescriptorSetManager.h"
#include "vulkan/caching/VulkanPipelineLayoutCache.h"
#include "vulkan/VulkanDescriptorSetCache.h"
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
#include "vulkan/VulkanPipelineLayoutCache.h"
#include "vulkan/memory/ResourceManager.h"
#include "vulkan/memory/ResourcePointer.h"
#include "vulkan/utils/Definitions.h"
@@ -137,7 +138,8 @@ private:
VulkanSamplerCache mSamplerCache;
VulkanBlitter mBlitter;
VulkanReadPixels mReadPixels;
VulkanDescriptorSetManager mDescriptorSetManager;
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
VulkanDescriptorSetCache mDescriptorSetCache;
VulkanQueryManager mQueryManager;
// This is necessary for us to write to push constants after binding a pipeline.
@@ -15,15 +15,12 @@
*/
#include "VulkanPipelineCache.h"
#include "VulkanMemory.h"
#include "caching/VulkanDescriptorSetManager.h"
#include <utils/Log.h>
#include <utils/Panic.h>
#include "VulkanConstants.h"
#include "VulkanHandles.h"
#include "VulkanTexture.h"
#include "vulkan/utils/Conversion.h"
#if defined(__clang__)
@@ -17,7 +17,8 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
#include <vulkan/VulkanHandles.h>
#include "VulkanHandles.h"
#include <bluevk/BlueVK.h>
#include <utils/Hash.h>
+60 -56
View File
@@ -55,63 +55,61 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
VK_COMPONENT_SWIZZLE_A,
};
auto const compose = [](VkComponentSwizzle out, VkComponentMapping const& prev,
uint8_t channelIndex) {
// We need to first change all identities to its equivalent channel.
if (out == VK_COMPONENT_SWIZZLE_IDENTITY) {
out = IDENTITY[channelIndex];
auto const compose = [](VkComponentMapping const& prev,
VkComponentMapping const& next) -> VkComponentMapping {
VkComponentSwizzle vals[4] = { next.r, next.g, next.b, next.a };
for (auto& out: vals) {
switch (out) {
case VK_COMPONENT_SWIZZLE_R:
out = prev.r;
break;
case VK_COMPONENT_SWIZZLE_G:
out = prev.g;
break;
case VK_COMPONENT_SWIZZLE_B:
out = prev.b;
break;
case VK_COMPONENT_SWIZZLE_A:
out = prev.a;
break;
// Do not modify the value
case VK_COMPONENT_SWIZZLE_IDENTITY:
case VK_COMPONENT_SWIZZLE_ZERO:
case VK_COMPONENT_SWIZZLE_ONE:
// Below is not exposed in Vulkan's API, but needs to be there for compilation.
case VK_COMPONENT_SWIZZLE_MAX_ENUM:
break;
}
}
switch (out) {
case VK_COMPONENT_SWIZZLE_R:
out = prev.r;
break;
case VK_COMPONENT_SWIZZLE_G:
out = prev.g;
break;
case VK_COMPONENT_SWIZZLE_B:
out = prev.b;
break;
case VK_COMPONENT_SWIZZLE_A:
out = prev.a;
break;
case VK_COMPONENT_SWIZZLE_IDENTITY:
case VK_COMPONENT_SWIZZLE_ZERO:
case VK_COMPONENT_SWIZZLE_ONE:
return out;
// Below is not exposed in Vulkan's API, but needs to be there for compilation.
case VK_COMPONENT_SWIZZLE_MAX_ENUM:
break;
}
// If the result correctly corresponds to the identity, just return identity.
if (IDENTITY[channelIndex] == out) {
return VK_COMPONENT_SWIZZLE_IDENTITY;
}
return out;
return { vals[0], vals[1], vals[2], vals[3] };
};
auto const identityToChannel = [](VkComponentSwizzle val, uint8_t channelIndex) {
if (val != VK_COMPONENT_SWIZZLE_IDENTITY) {
return val;
auto const identityToChannel = [](VkComponentMapping const& mapping) -> VkComponentMapping {
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
for (uint8_t i = 0; i < 4; i++) {
if (vals[i] != VK_COMPONENT_SWIZZLE_IDENTITY) {
continue;
}
vals[i] = IDENTITY[i];
}
return IDENTITY[channelIndex];
return { vals[0], vals[1], vals[2], vals[3] };
};
auto const channelToIdentity = [](VkComponentMapping const& mapping) -> VkComponentMapping {
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
for (uint8_t i = 0; i < 4; i++) {
if (IDENTITY[i] != vals[i]) {
continue;
}
vals[i] = VK_COMPONENT_SWIZZLE_IDENTITY;
}
return { vals[0], vals[1], vals[2], vals[3] };
};
// We make sure all all identities are mapped into respective channels so that actual channel
// mapping will be passed onto the output.
VkComponentMapping const prevExplicit = {
identityToChannel(prev.r, 0),
identityToChannel(prev.g, 1),
identityToChannel(prev.b, 2),
identityToChannel(prev.a, 3),
};
// Note that the channel index corresponds to the VkComponentMapping struct layout.
return {
compose(next.r, prevExplicit, 0),
compose(next.g, prevExplicit, 1),
compose(next.b, prevExplicit, 2),
compose(next.a, prevExplicit, 3),
};
VkComponentMapping const prevExplicit = identityToChannel(prev);
VkComponentMapping const nextExplicit = identityToChannel(next);
return channelToIdentity(compose(prevExplicit, nextExplicit));
}
inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
@@ -153,7 +151,6 @@ uint8_t getLayerCountFromDepth(uint32_t const depth) {
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
}
} // anonymous namespace
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
@@ -249,12 +246,19 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
// Determine if we can use the transient usage flag combined with lazily allocated memory.
const bool useTransientAttachment =
// Lazily allocated memory is available.
context.isLazilyAllocatedMemorySupported() &&
// Usage consists of attachment flags only.
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
// Usage contains at least one attachment flag.
any(tusage & TextureUsage::ALL_ATTACHMENTS);
// Lazily allocated memory is available.
context.isLazilyAllocatedMemorySupported() &&
// Usage consists of attachment flags only.
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
// Usage contains at least one attachment flag.
any(tusage & TextureUsage::ALL_ATTACHMENTS) &&
// Depth resolve cannot use transient attachment because it uses a custom shader.
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
// restriction.
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
// and above to be able to support stencil resolve (along with depth).
!(any(usage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
mState->mIsTransientAttachment = useTransientAttachment;
const VkImageUsageFlags transientFlag =
@@ -736,10 +736,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
// We know we need to allocate the protected version of the VK objects
context.mProtectedMemorySupported =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
vkGetPhysicalDeviceProperties2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceProperties);
@@ -759,6 +755,10 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
mImpl->mGraphicsQueueIndex = 0;
}
// We know we need to allocate the protected version of the VK objects
context.mProtectedMemorySupported =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
if (context.mProtectedMemorySupported) {
mImpl->mProtectedGraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(
mImpl->mPhysicalDevice, (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
@@ -1000,6 +1000,15 @@ VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chrom
return createExternalImageViewImpl(mImpl->mDevice, chroma, internalFormat, image, range,
viewType, swizzle);
}
ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() const {
return getSwapchainInstanceExtensionsImpl();
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VkInstance instance, uint64_t flags) const noexcept {
return createVkSurfaceKHRImpl(nativeWindow, instance, flags);
}
#undef SWAPCHAIN_RET_FUNC
}// namespace filament::backend
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <backend/platforms/VulkanPlatform.h>
#include <backend/platforms/VulkanPlatformAndroid.h>
#include <backend/DriverEnums.h>
#include <backend/platforms/VulkanPlatformAndroid.h>
#include <private/backend/BackendUtilsAndroid.h>
#include "vulkan/VulkanConstants.h"
@@ -157,7 +156,7 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
};
VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkImageCreateInfo imageInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.pNext = &externalCreateInfo;
imageInfo.format = metadata.format;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
@@ -200,14 +199,12 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
return data;
}
} // namespace
}// namespace
namespace fvkandroid {
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
bool sRGB) noexcept {
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
AHardwareBuffer const* buffer, bool sRGB) noexcept {
if (__builtin_available(android 26, *)) {
AHardwareBuffer_Desc hardwareBufferDescription = {};
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
@@ -226,12 +223,23 @@ Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
return Platform::ExternalImageHandle{};
}
} // namespace fvkandroid
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
ExternalImageHandleRef externalImage, VkDevice device) {
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
ExternalImageHandleRef externalImage) const noexcept {
auto const* fvkExternalImage =
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
return {
.width = fvkExternalImage->width,
.height = fvkExternalImage->height,
.format = fvkExternalImage->format,
.usage = fvkExternalImage->usage,
};
}
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
ExternalImageHandleRef externalImage) {
auto const* fvkExternalImage =
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
ExternalImageMetadata metadata;
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
@@ -245,7 +253,7 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
std::tie(metadata.format, metadata.usage) =
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
}
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
@@ -256,11 +264,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
.pNext = &formatInfo,
};
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(getDevice(), buffer, &properties);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkGetAndroidHardwareBufferProperties failed with error="
<< static_cast<int32_t>(result);
<< "vkGetAndroidHardwareBufferProperties failed with error="
<< static_cast<int32_t>(result);
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
<< "mismatched image format( " << metadata.format << ") and queried format("
@@ -271,14 +279,14 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
return metadata;
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
ExternalImageHandleRef externalImage, VkDevice device,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
auto const* fvkExternalImage =
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata,
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
memoryTypeIndex, usage);
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
return data;
@@ -397,14 +405,14 @@ VkSampler VulkanPlatform::createExternalSamplerImpl(
return sampler;
}
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
return {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
};
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* nativeWindow,
VkInstance instance, uint64_t flags) const noexcept {
VkSurfaceKHR surface;
VkExtent2D extent;
@@ -416,6 +424,26 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateAndroidSurfaceKHR with error=" << static_cast<int32_t>(result);
return {surface, extent};
return { surface, extent };
}
// Deprecated platform dependent helper methods
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() { return {}; }
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
ExternalImageHandleRef externalImage, VkDevice device) {
return ExternalImageMetadata{};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
ExternalImageHandleRef externalImage, VkDevice device,
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
return ImageData{};
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
return SurfaceBundle{};
}
}// namespace filament::backend
@@ -52,7 +52,7 @@ using namespace bluevk;
namespace filament::backend {
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
ExtensionSet const ret = {
#if defined(__APPLE__)
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
@@ -87,7 +87,7 @@ VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
return VK_NULL_HANDLE;
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface;
#if defined(__APPLE__)
@@ -108,7 +108,7 @@ VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
return VK_NULL_HANDLE;
}
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
VulkanPlatform::ExtensionSet const ret = {
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
@@ -126,7 +126,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
return ret;
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface;
+2 -2
View File
@@ -651,11 +651,11 @@ uint8_t WebGPUDriver::getMaxDrawBuffers() {
return MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT;
}
size_t WebGPUDriver::getMaxUniformBufferSize(SamplerType) {
size_t WebGPUDriver::getMaxUniformBufferSize() {
return 16384u;
}
size_t WebGPUDriver::getMaxTextureSize() {
size_t WebGPUDriver::getMaxTextureSize(SamplerType target) {
return 2048u;
}
@@ -143,7 +143,7 @@ wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
return device;
}
Driver* WebGPUPlatform::createDriver(void* const sharedContext,
Driver* WebGPUPlatform::createDriver(void* sharedContext,
const Platform::DriverConfig& /*driverConfig*/) noexcept {
if (sharedContext) {
FWGPU_LOGW << "sharedContext is ignored/unused in the WebGPU backend. A non-null "
@@ -15,6 +15,8 @@
*/
#include <backend/platforms/WebGPUPlatform.h>
#include <backend/DriverEnums.h>
#include <utils/Panic.h>
#include <webgpu/webgpu_cpp.h>
@@ -118,7 +120,9 @@ wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t flags)
if (useXcb) {
wgpu::SurfaceSourceXCBWindow surfaceSourceXcb{};
surfaceSourceXcb.connection = g_x11.connection;
surfaceSourceXcb.window = reinterpret_cast<uint32_t>(nativeWindow);
// TODO: this looks really wrong, please fix!!
surfaceSourceXcb.window = *((uint32_t*) nativeWindow);
wgpu::SurfaceDescriptor surfaceDescriptor{
.nextInChain = &surfaceSourceXcb,
.label = "linux_xcb_surface"
+9 -3
View File
@@ -64,9 +64,8 @@ class ColorSpace;
* Performance
* ===========
*
* Creating a new ColorGrading object may be more expensive than other Filament objects as a
* 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on
* the CPU.
* Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may
* need to be generated. The generation of this LUT, if necessary, may happen on the CPU.
*
* Ordering
* ========
@@ -155,6 +154,9 @@ public:
* 3D texture. For instance, a low quality level will use a 16x16x16 10 bit LUT, a medium
* quality level will use a 32x32x32 10 bit LUT, a high quality will use a 32x32x32 16 bit
* LUT, and a ultra quality will use a 64x64x64 16 bit LUT.
*
* This setting has no effect if generating a 1D LUT.
*
* This overrides the values set by format() and dimensions().
*
* The default quality is medium.
@@ -169,6 +171,8 @@ public:
* When color grading is implemented using a 3D LUT, this sets the texture format of
* of the LUT. This overrides the value set by quality().
*
* This setting has no effect if generating a 1D LUT.
*
* The default is INTEGER
*
* @param format The desired format of the 3D LUT.
@@ -181,6 +185,8 @@ public:
* When color grading is implemented using a 3D LUT, this sets the dimension of the LUT.
* This overrides the value set by quality().
*
* This setting has no effect if generating a 1D LUT.
*
* The default is 32
*
* @param dim The desired dimension of the LUT. Between 16 and 64.
+31
View File
@@ -68,6 +68,21 @@ struct UTILS_PUBLIC ToneMapper {
* function applied ("linear")
*/
virtual math::float3 operator()(math::float3 c) const noexcept = 0;
/**
* If true, then this function holds that f(x) = vec3(f(x.r), f(x.g), f(x.b))
*
* This may be used to indicate that the color grading's LUT only requires a 1D texture instead
* of a 3D texture, potentially saving a significant amount of memory and generation time.
*/
virtual bool isOneDimensional() const noexcept { return false; }
/**
* True if this tonemapper only works in low-dynamic-range.
*
* This may be used to indicate that the color grading's LUT doesn't need to be log encoded.
*/
virtual bool isLDR() const noexcept { return false; }
};
/**
@@ -79,6 +94,8 @@ struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper {
~LinearToneMapper() noexcept final;
math::float3 operator()(math::float3 c) const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return true; }
};
/**
@@ -91,6 +108,8 @@ struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper {
~ACESToneMapper() noexcept final;
math::float3 operator()(math::float3 c) const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
/**
@@ -104,6 +123,8 @@ struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper {
~ACESLegacyToneMapper() noexcept final;
math::float3 operator()(math::float3 c) const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
/**
@@ -117,6 +138,8 @@ struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
~FilmicToneMapper() noexcept final;
math::float3 operator()(math::float3 x) const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return false; }
};
/**
@@ -129,6 +152,8 @@ struct UTILS_PUBLIC PBRNeutralToneMapper final : public ToneMapper {
~PBRNeutralToneMapper() noexcept final;
math::float3 operator()(math::float3 x) const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
/**
@@ -150,6 +175,8 @@ struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper {
~AgxToneMapper() noexcept final;
math::float3 operator()(math::float3 x) const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
AgxLook look;
};
@@ -194,6 +221,8 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept;
math::float3 operator()(math::float3 x) const noexcept override;
bool isOneDimensional() const noexcept override { return true; }
bool isLDR() const noexcept override { return false; }
/** Returns the contrast of the curve as a strictly positive value. */
float getContrast() const noexcept;
@@ -256,6 +285,8 @@ struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper {
~DisplayRangeToneMapper() noexcept override;
math::float3 operator()(math::float3 c) const noexcept override;
bool isOneDimensional() const noexcept override { return false; }
bool isLDR() const noexcept override { return false; }
};
} // namespace filament
+72 -56
View File
@@ -2306,36 +2306,11 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
const FColorGrading* colorGrading, ColorGradingConfig const& colorGradingConfig,
VignetteOptions const& vignetteOptions, uint32_t const width, uint32_t const height) noexcept {
float4 const vignetteParameters = getVignetteParameters(vignetteOptions, width, height);
auto const& material = getPostProcessMaterial("colorGradingAsSubpass");
FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(mEngine, material);
mi->setParameter("lut", colorGrading->getHwHandle(), {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR,
.wrapS = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapT = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapR = SamplerWrapMode::CLAMP_TO_EDGE,
.anisotropyLog2 = 0
});
const float lutDimension = float(colorGrading->getDimension());
mi->setParameter("lutSize", float2{
0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension,
});
const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine());
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
mi->setParameter("dithering", colorGradingConfig.dithering);
mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
mi->setParameter("temporalNoise", temporalNoise);
auto& material = getPostProcessMaterial("colorGradingAsSubpass");
FMaterialInstance* const mi =
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
vignetteOptions, width, height);
mi->commit(driver);
// load both variants
material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
material.getMaterial(mEngine, PostProcessVariant::TRANSLUCENT);
}
void PostProcessManager::colorGradingSubpass(DriverApi& driver,
@@ -2487,22 +2462,14 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
auto const& out = resources.getRenderPassInfo();
auto const& material = getPostProcessMaterial("colorGrading");
PostProcessVariant const variant = colorGradingConfig.translucent ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
auto const& input = resources.getDescriptor(data.input);
auto const& output = resources.getDescriptor(data.output);
auto& material = getPostProcessMaterial("colorGrading");
FMaterialInstance* const mi =
PostProcessMaterial::getMaterialInstance(mEngine, material, variant);
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
vignetteOptions, output.width, output.height);
mi->setParameter("lut", colorGrading->getHwHandle(), {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
const float lutDimension = float(colorGrading->getDimension());
mi->setParameter("lutSize", float2{
0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension,
});
mi->setParameter("colorBuffer", colorTexture, { /* shader uses texelFetch */ });
mi->setParameter("bloomBuffer", bloomTexture, {
.filterMag = SamplerMagFilter::LINEAR,
@@ -2534,19 +2501,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
bloomParameters.y = 1.0f - bloomParameters.x;
}
auto const& input = resources.getDescriptor(data.input);
auto const& output = resources.getDescriptor(data.output);
float4 const vignetteParameters = getVignetteParameters(
vignetteOptions, output.width, output.height);
const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine());
mi->setParameter("dithering", colorGradingConfig.dithering);
mi->setParameter("bloom", bloomParameters);
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
mi->setParameter("temporalNoise", temporalNoise);
mi->setParameter("viewport", float4{
float(vp.left) / input.width,
float(vp.bottom) / input.height,
@@ -2554,7 +2509,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
float(vp.height) / input.height
});
commitAndRenderFullScreenQuad(driver, out, mi, variant);
commitAndRenderFullScreenQuad(driver, out, mi,
colorGradingConfig.translucent
? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
}
);
@@ -2692,11 +2649,70 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma);
if (dirty) {
ma->invalidate();
// TODO: call Material::compile(), we can't si that now because it works only
// TODO: call Material::compile(), we can't do that now because it works only
// with surface materials
}
}
FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
PostProcessMaterial& material, FColorGrading const* colorGrading,
ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
uint32_t const width, uint32_t const height) noexcept {
FMaterial* const ma = material.getMaterial(mEngine);
bool dirty = false;
auto setConstantParameter =
[&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept {
auto id = material->getSpecializationConstantId(name);
if (id.has_value()) {
if (material->setConstant(id.value(), value)) {
dirty = true;
}
}
};
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional());
setConstantParameter(ma, "isLDR", colorGrading->isLDR());
if (dirty) {
ma->invalidate();
// TODO: call Material::compile(), we can't do that now because it works only
// with surface materials
}
PostProcessVariant const variant = colorGradingConfig.translucent ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
FMaterialInstance* const mi =
PostProcessMaterial::getMaterialInstance(mEngine, material, variant);
const SamplerParams params = {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR,
.wrapS = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapT = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapR = SamplerWrapMode::CLAMP_TO_EDGE,
.anisotropyLog2 = 0
};
mi->setParameter("lut", colorGrading->getHwHandle(), params);
const float lutDimension = float(colorGrading->getDimension());
mi->setParameter("lutSize", float2{
0.5f / lutDimension, (lutDimension - 1.0f) / lutDimension,
});
const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine());
float4 const vignetteParameters = getVignetteParameters(vignetteOptions, width, height);
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
mi->setParameter("dithering", colorGradingConfig.dithering);
mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
mi->setParameter("temporalNoise", temporalNoise);
return mi;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphId<FrameGraphTexture> const depth,
+7
View File
@@ -401,6 +401,13 @@ public:
FMaterialInstance const* mi,
PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept;
// Sets the necessary spec constants and uniforms common to both colorGrading.mat and
// colorGradingAsSubpass.mat.
FMaterialInstance* configureColorGradingMaterial(
PostProcessMaterial& material, FColorGrading const* colorGrading,
ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
uint32_t const width, uint32_t const height) noexcept;
private:
backend::RenderPrimitiveHandle mFullScreenQuadRph;
backend::VertexBufferInfoHandle mFullScreenQuadVbih;
+194 -160
View File
@@ -35,7 +35,6 @@
#include <cmath>
#include <cstdlib>
#include <mutex>
#include <tuple>
namespace filament {
@@ -581,8 +580,11 @@ static float3 luminanceScaling(float3 x,
// Quality
//------------------------------------------------------------------------------
static std::tuple<TextureFormat, PixelDataFormat, PixelDataType>
selectLutTextureParams(ColorGrading::LutFormat const lutFormat) noexcept {
static std::tuple<TextureFormat, PixelDataFormat, PixelDataType> selectLutTextureParams(
ColorGrading::LutFormat const lutFormat, const bool isOneDimensional) noexcept {
if (isOneDimensional) {
return { TextureFormat::R16F, PixelDataFormat::R, PixelDataType::HALF };
}
// We use RGBA16F for high quality modes instead of RGB16F because RGB16F
// is not supported everywhere
switch (lutFormat) {
@@ -658,27 +660,44 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
DriverApi& driver = engine.getDriverApi();
Config c;
// This lock protects the data inside Config, which is written to by the Filament thread,
// and read from multiple Job threads.
Mutex configLock;
{
std::lock_guard<Mutex> const lock(configLock);
c.lutDimension = builder->dimension;
c.adaptationTransform = adaptationTransform(builder->whiteBalance);
c.colorGradingIn = selectColorGradingTransformIn(builder->toneMapping);
c.colorGradingOut = selectColorGradingTransformOut(builder->toneMapping);
c.colorGradingLuminance = selectColorGradingLuminance(builder->toneMapping);
c.oetf = selectOETF(builder->outputColorSpace);
// XXX: The following two conditions also only hold true as long as the input and output color
// spaces are the same, but we currently don't check that. We must revise these conditions if we
// ever handle this case.
mIsOneDimensional = !builder->hasAdjustments && !builder->luminanceScaling
&& builder->toneMapper->isOneDimensional()
&& engine.features.engine.color_grading.use_1d_lut;
mIsLDR = mIsOneDimensional && builder->toneMapper->isLDR();
const Config config = {
mIsOneDimensional ? 512u : builder->dimension,
adaptationTransform(builder->whiteBalance),
selectColorGradingTransformIn(builder->toneMapping),
selectColorGradingTransformOut(builder->toneMapping),
selectColorGradingLuminance(builder->toneMapping),
selectOETF(builder->outputColorSpace),
};
mDimension = config.lutDimension;
uint32_t width;
uint32_t height;
uint32_t depth;
if (mIsOneDimensional) {
width = config.lutDimension;
height = 1;
depth = 1;
} else {
width = config.lutDimension;
height = config.lutDimension;
depth = config.lutDimension;
}
mDimension = c.lutDimension;
size_t lutElementCount = c.lutDimension * c.lutDimension * c.lutDimension;
size_t elementSize = sizeof(half4);
size_t lutElementCount = width * height * depth;
size_t elementSize = mIsOneDimensional ? sizeof(half) : sizeof(half4);
void* data = malloc(lutElementCount * elementSize);
auto [textureFormat, format, type] = selectLutTextureParams(builder->format);
auto [textureFormat, format, type] =
selectLutTextureParams(builder->format, mIsOneDimensional);
assert_invariant(FTexture::isTextureFormatSupported(engine, textureFormat));
assert_invariant(FTexture::validatePixelFormatAndType(textureFormat, format, type));
@@ -688,170 +707,185 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
converted = malloc(lutElementCount * sizeof(uint32_t));
}
auto hdrColorAt = [builder, config](size_t r, size_t g, size_t b) {
float3 v = float3{r, g, b} * (1.0f / float(config.lutDimension - 1u));
// LogC encoding
v = LogC_to_linear(v);
// Kill negative values near 0.0f due to imprecision in the log conversion
v = max(v, 0.0f);
if (builder->hasAdjustments) {
// Exposure
v = adjustExposure(v, builder->exposure);
// Purkinje shift ("low-light" vision)
v = scotopicAdaptation(v, builder->nightAdaptation);
}
// Move to color grading color space
v = config.colorGradingIn * v;
if (builder->hasAdjustments) {
// White balance
v = chromaticAdaptation(v, config.adaptationTransform);
// Kill negative values before the next transforms
v = max(v, 0.0f);
// Channel mixer
v = channelMixer(v, builder->outRed, builder->outGreen, builder->outBlue);
// Shadows/mid-tones/highlights
v = tonalRanges(v, config.colorGradingLuminance,
builder->shadows, builder->midtones, builder->highlights,
builder->tonalRanges);
// The adjustments below behave better in log space
v = linear_to_LogC(v);
// ASC CDL
v = colorDecisionList(v, builder->slope, builder->offset, builder->power);
// Contrast in log space
v = contrast(v, builder->contrast);
// Back to linear space
v = LogC_to_linear(v);
// Vibrance in linear space
v = vibrance(v, config.colorGradingLuminance, builder->vibrance);
// Saturation in linear space
v = saturation(v, config.colorGradingLuminance, builder->saturation);
// Kill negative values before curves
v = max(v, 0.0f);
// RGB curves
v = curves(v,
builder->shadowGamma, builder->midPoint, builder->highlightScale);
}
// Tone mapping
if (builder->luminanceScaling) {
v = luminanceScaling(v, *builder->toneMapper, config.colorGradingLuminance);
} else {
v = (*builder->toneMapper)(v);
}
// Go back to display color space
v = config.colorGradingOut * v;
// Apply gamut mapping
if (builder->gamutMapping) {
// TODO: This should depend on the output color space
v = gamutMapping_sRGB(v);
}
// TODO: We should convert to the output color space if we use a working
// color space that's not sRGB
// TODO: Allow the user to customize the output color space
// We need to clamp for the output transfer function
v = saturate(v);
// Apply OETF
v = config.oetf(v);
return v;
};
//auto now = std::chrono::steady_clock::now();
// Multithreadedly generate the tone mapping 3D look-up table using 32 jobs
// Slices are 8 KiB (128 cache lines) apart.
// This takes about 3-6ms on Android in Release
JobSystem& js = engine.getJobSystem();
auto *slices = js.createJob();
for (size_t b = 0; b < c.lutDimension; b++) {
auto *job = js.createJob(slices,
[data, converted, b, &c, &configLock, builder](JobSystem&, JobSystem::Job*) {
Config config;
{
std::lock_guard<Mutex> lock(configLock);
config = c;
if (mIsOneDimensional) {
half* UTILS_RESTRICT p = (half*) data;
if (mIsLDR) {
for (size_t rgb = 0; rgb < config.lutDimension; rgb++) {
float3 v = float3(rgb) * (1.0f / float(config.lutDimension - 1u));
v = (*builder->toneMapper)(float3(v));
// We need to clamp for the output transfer function
v = saturate(v);
// Apply OETF
v = config.oetf(v);
*p++ = half(v.r);
}
half4* UTILS_RESTRICT p = (half4*) data + b * config.lutDimension * config.lutDimension;
for (size_t g = 0; g < config.lutDimension; g++) {
for (size_t r = 0; r < config.lutDimension; r++) {
float3 v = float3{r, g, b} * (1.0f / float(config.lutDimension - 1u));
// LogC encoding
v = LogC_to_linear(v);
// Kill negative values near 0.0f due to imprecision in the log conversion
v = max(v, 0.0f);
if (builder->hasAdjustments) {
// Exposure
v = adjustExposure(v, builder->exposure);
// Purkinje shift ("low-light" vision)
v = scotopicAdaptation(v, builder->nightAdaptation);
} else {
for (size_t rgb = 0; rgb < config.lutDimension; rgb++) {
*p++ = half(hdrColorAt(rgb, rgb, rgb).r);
}
}
} else {
// Multithreadedly generate the tone mapping 3D look-up table using 32 jobs
// Slices are 8 KiB (128 cache lines) apart.
// This takes about 3-6ms on Android in Release
JobSystem& js = engine.getJobSystem();
auto *slices = js.createJob();
for (size_t b = 0; b < config.lutDimension; b++) {
auto* job = js.createJob(slices,
[data, converted, b, &config, builder, &hdrColorAt](
JobSystem&, JobSystem::Job*) {
half4* UTILS_RESTRICT p =
(half4*) data + b * config.lutDimension * config.lutDimension;
for (size_t g = 0; g < config.lutDimension; g++) {
for (size_t r = 0; r < config.lutDimension; r++) {
*p++ = half4{hdrColorAt(r, g, b), 0.0f};
}
// Move to color grading color space
v = c.colorGradingIn * v;
if (builder->hasAdjustments) {
// White balance
v = chromaticAdaptation(v, config.adaptationTransform);
// Kill negative values before the next transforms
v = max(v, 0.0f);
// Channel mixer
v = channelMixer(v, builder->outRed, builder->outGreen, builder->outBlue);
// Shadows/mid-tones/highlights
v = tonalRanges(v, c.colorGradingLuminance,
builder->shadows, builder->midtones, builder->highlights,
builder->tonalRanges);
// The adjustments below behave better in log space
v = linear_to_LogC(v);
// ASC CDL
v = colorDecisionList(v, builder->slope, builder->offset, builder->power);
// Contrast in log space
v = contrast(v, builder->contrast);
// Back to linear space
v = LogC_to_linear(v);
// Vibrance in linear space
v = vibrance(v, c.colorGradingLuminance, builder->vibrance);
// Saturation in linear space
v = saturation(v, c.colorGradingLuminance, builder->saturation);
// Kill negative values before curves
v = max(v, 0.0f);
// RGB curves
v = curves(v,
builder->shadowGamma, builder->midPoint, builder->highlightScale);
}
// Tone mapping
if (builder->luminanceScaling) {
v = luminanceScaling(v, *builder->toneMapper, c.colorGradingLuminance);
} else {
v = (*builder->toneMapper)(v);
}
// Go back to display color space
v = c.colorGradingOut * v;
// Apply gamut mapping
if (builder->gamutMapping) {
// TODO: This should depend on the output color space
v = gamutMapping_sRGB(v);
}
// TODO: We should convert to the output color space if we use a working
// color space that's not sRGB
// TODO: Allow the user to customize the output color space
// We need to clamp for the output transfer function
v = saturate(v);
// Apply OETF
v = c.oetf(v);
*p++ = half4{v, 0.0f};
}
}
if (converted) {
uint32_t* const UTILS_RESTRICT dst = (uint32_t*) converted +
b * config.lutDimension * config.lutDimension;
half4* UTILS_RESTRICT src = (half4*) data +
b * config.lutDimension * config.lutDimension;
// we use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight
// 32-bits results in one go.
const size_t count = (config.lutDimension * config.lutDimension) & ~0x7u; // tell the compiler that we're a multiple of 8
if (converted) {
uint32_t* const UTILS_RESTRICT dst = (uint32_t*) converted +
b * config.lutDimension * config.lutDimension;
half4* UTILS_RESTRICT src = (half4*) data +
b * config.lutDimension * config.lutDimension;
// we use a vectorize width of 8 because, on ARMv8 it allows the compiler to
// write eight 32-bits results in one go.
const size_t count = (config.lutDimension * config.lutDimension) & ~0x7u; // tell the compiler that we're a multiple of 8
#if defined(__clang__)
#pragma clang loop vectorize_width(8)
#pragma clang loop vectorize_width(8)
#endif
for (size_t i = 0; i < count; ++i) {
float4 v{src[i]};
uint32_t pr = uint32_t(std::floor(v.x * 1023.0f + 0.5f));
uint32_t pg = uint32_t(std::floor(v.y * 1023.0f + 0.5f));
uint32_t pb = uint32_t(std::floor(v.z * 1023.0f + 0.5f));
dst[i] = (pb << 20u) | (pg << 10u) | pr;
for (size_t i = 0; i < count; ++i) {
float4 v{src[i]};
uint32_t pr = uint32_t(std::floor(v.x * 1023.0f + 0.5f));
uint32_t pg = uint32_t(std::floor(v.y * 1023.0f + 0.5f));
uint32_t pb = uint32_t(std::floor(v.z * 1023.0f + 0.5f));
dst[i] = (pb << 20u) | (pg << 10u) | pr;
}
}
}
});
js.run(job);
}
});
js.run(job);
// TODO: Should we do a runAndRetain() and defer the wait() + texture creation until
// getHwHandle() is invoked?
js.runAndWait(slices);
}
// TODO: Should we do a runAndRetain() and defer the wait() + texture creation until
// getHwHandle() is invoked?
js.runAndWait(slices);
//std::chrono::duration<float, std::milli> duration = std::chrono::steady_clock::now() - now;
//slog.d << "LUT generation time: " << duration.count() << " ms" << io::endl;
mLutHandle = driver.createTexture(
SamplerType::SAMPLER_3D,
1,
textureFormat,
1,
c.lutDimension,
c.lutDimension,
c.lutDimension,
TextureUsage::DEFAULT
);
if (converted) {
free(data);
data = converted;
elementSize = sizeof(uint32_t);
}
// Create texture.
mLutHandle = driver.createTexture(SamplerType::SAMPLER_3D, 1, textureFormat, 1,
width, height, depth, TextureUsage::DEFAULT);
driver.update3DImage(mLutHandle, 0,
0, 0, 0,
c.lutDimension, c.lutDimension, c.lutDimension,
width, height, depth,
PixelBufferDescriptor{
data, lutElementCount * elementSize,format, type,
[](void* buffer, size_t, void*) { free(buffer); }
}
);
data, lutElementCount * elementSize, format, type,
[](void* buffer, size_t, void*) { free(buffer); }
});
}
FColorGrading::~FColorGrading() noexcept = default;
+4 -1
View File
@@ -42,12 +42,15 @@ public:
void terminate(FEngine& engine);
backend::TextureHandle getHwHandle() const noexcept { return mLutHandle; }
uint32_t getDimension() const noexcept { return mDimension; }
bool isOneDimensional() const noexcept { return mIsOneDimensional; }
bool isLDR() const noexcept { return mIsLDR; }
private:
backend::TextureHandle mLutHandle;
uint32_t mDimension;
bool mIsOneDimensional;
bool mIsLDR;
};
FILAMENT_DOWNCAST(ColorGrading)
+6
View File
@@ -687,6 +687,9 @@ public:
struct {
struct {
struct {
bool use_1d_lut = false;
} color_grading;
struct {
bool use_shadow_atlas = false;
} shadows;
@@ -719,6 +722,9 @@ public:
{ "backend.opengl.assert_native_window_is_valid",
"Asserts that the ANativeWindow is valid when rendering starts.",
&features.backend.opengl.assert_native_window_is_valid, true },
{ "engine.color_grading.use_1d_lut",
"Uses a 1D LUT for color grading.",
&features.engine.color_grading.use_1d_lut, false },
{ "engine.shadows.use_shadow_atlas",
"Uses an array of atlases to store shadow maps.",
&features.engine.shadows.use_shadow_atlas, false },
+4 -3
View File
@@ -153,9 +153,10 @@ Texture::Builder& Texture::Builder::name(const char* name, size_t const len) noe
}
Texture* Texture::Builder::build(Engine& engine) {
FILAMENT_CHECK_PRECONDITION(Texture::isTextureFormatSupported(engine, mImpl->mFormat))
<< "Texture format " << uint16_t(mImpl->mFormat) << " not supported on this platform";
if (mImpl->mTarget != SamplerType::SAMPLER_EXTERNAL) {
FILAMENT_CHECK_PRECONDITION(Texture::isTextureFormatSupported(engine, mImpl->mFormat))
<< "Texture format " << uint16_t(mImpl->mFormat) << " not supported on this platform";
}
const bool isProtectedTexturesSupported =
downcast(engine).getDriverApi().isProtectedTexturesSupported();
const bool useProtectedMemory = bool(mImpl->mUsage & TextureUsage::PROTECTED);
@@ -1,13 +1,29 @@
vec3 colorGrade(mediump sampler3D lut, const vec3 x) {
vec3 LogC_to_linear(const vec3 x) {
// Alexa LogC EI 1000
const float a = 5.555556;
const float b = 0.047996;
const float c = 0.244161 / log2(10.0);
const float d = 0.386036;
vec3 logc = c * log2(a * x + b) + d;
return c * log2(a * x + b) + d;
}
// Remap to sample pixel centers
logc = materialParams.lutSize.x + logc * materialParams.lutSize.y;
vec3 colorGrade3D(mediump sampler3D lut, const vec3 v) {
return textureLod(lut, v, 0.0).rgb;
}
return textureLod(lut, logc, 0.0).rgb;
vec3 colorGrade1D(mediump sampler3D lut, const vec3 v) {
return vec3(
textureLod(lut, vec3(v.r, 0.5, 0.5), 0.0).r,
textureLod(lut, vec3(v.g, 0.5, 0.5), 0.0).r,
textureLod(lut, vec3(v.b, 0.5, 0.5), 0.0).r);
}
vec3 colorGrade(mediump sampler3D lut, vec3 v) {
if (!materialConstants_isLDR) {
v = LogC_to_linear(v);
}
// Remap to sample pixel centers.
v = materialParams.lutSize.x + v * materialParams.lutSize.y;
return materialConstants_isOneDimensional
? colorGrade1D(lut, v) : colorGrade3D(lut, v);
}
@@ -66,6 +66,16 @@ material {
precision : high
}
],
constants : [
{
type : bool,
name : isOneDimensional
},
{
type : bool,
name : isLDR
}
],
variables : [
vertex
],
@@ -154,7 +164,7 @@ void postProcess(inout PostProcessInputs postProcess) {
}
// Color grading
color.rgb = colorGrade(materialParams_lut, color.rgb);
color.rgb = colorGrade(materialParams_lut, color.rgb);
// output in premultiplied alpha
#if !POST_PROCESS_OPAQUE
@@ -32,6 +32,16 @@ material {
name : vignetteColor
}
],
constants : [
{
type : bool,
name : isOneDimensional
},
{
type : bool,
name : isLDR
}
],
subpasses : [
{
type : subpassInput,
@@ -103,7 +113,7 @@ void postProcess(inout PostProcessInputs postProcess) {
}
// Color grading
color.rgb = colorGrade(materialParams_lut, color.rgb);
color.rgb = colorGrade(materialParams_lut, color.rgb);
// output in premultiplied alpha
#if !POST_PROCESS_OPAQUE
+5
View File
@@ -88,7 +88,12 @@ void minLeftMaxRight(inout vec4 a, inout vec4 b, inout vec4 c, inout vec4 d, ino
// - we can't use a function because offset must be a constant expression
// - we can't use line continuation because that's not supported on desktop
#ifdef TARGET_WEBGPU_ENVIRONMENT
//WebGPU can not handle texelFetchOffset without an error about "ConstOffset is only permitted...".
#define makeSample(ij, o) vec4(texelFetch(materialParams_dof, ij+o, 0).rgb, texelFetch(materialParams_alpha, ij+o, 0).r)
#else
#define makeSample(ij, o) vec4(texelFetchOffset(materialParams_dof, ij, 0, o).rgb, texelFetchOffset(materialParams_alpha, ij, 0, o).r)
#endif
vec4 median(ivec2 ij) {
vec4 v[9];
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.58.0"
spec.version = "1.58.1"
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.58.0/filament-v1.58.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.1/filament-v1.58.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
+13 -5
View File
@@ -31,13 +31,17 @@ if (WIN32)
set(SRCS ${SRCS} src/BlueGLCoreWindowsImpl.S)
endif()
elseif (APPLE AND NOT IOS)
set(SRCS ${SRCS} src/BlueGLDarwin.cpp)
if (FILAMENT_SUPPORTS_OSMESA)
set(SRCS ${SRCS} src/BlueGLOSMesa.cpp)
else()
set(SRCS ${SRCS} src/BlueGLDarwin.cpp)
endif()
set(SRCS ${SRCS} src/BlueGLCoreDarwinUniversalImpl.S)
elseif(LINUX)
if(FILAMENT_SUPPORTS_EGL_ON_LINUX)
if (FILAMENT_SUPPORTS_EGL_ON_LINUX)
set(SRCS ${SRCS} src/BlueGLLinuxEGL.cpp)
elseif(FILAMENT_SUPPORTS_OSMESA)
set(SRCS ${SRCS} src/BlueGLLinuxOSMesa.cpp)
elseif (FILAMENT_SUPPORTS_OSMESA)
set(SRCS ${SRCS} src/BlueGLOSMesa.cpp)
else()
set(SRCS ${SRCS} src/BlueGLLinux.cpp)
endif()
@@ -53,7 +57,11 @@ include_directories(${PUBLIC_HDR_DIR})
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
if(FILAMENT_SUPPORTS_OSMESA)
target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL)
if (APPLE)
target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include)
else()
target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL)
endif()
endif()
# specify where the public headers of this library are
@@ -17,42 +17,64 @@
#include <dlfcn.h>
#include <string.h>
#if defined(__linux__)
#include <osmesa.h>
// This is to ensure that linking during compilation will not fail even if
// OSMesaGetProcAddress is not linked.
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
#elif defined(__APPLE__)
#include <GL/osmesa.h>
#endif // __linux__
#if defined(__linux__)
#endif
namespace bluegl {
namespace {
using ProcAddressFunc = void*(*)(char const* funcName);
}
// This is to ensure that linking during compilation will not fail even if
// OSMesaGetProcAddress is not linked.
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
struct Driver {
ProcAddressFunc OSMesaGetProcAddress;
void* library;
} g_driver = {nullptr, nullptr};
bool initBinder() {
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
static constexpr char const* libraryNames[] = {
#if defined(__linux__)
"libOSMesa.so",
"libosmesa.so",
#elif defined(__APPLE__)
"libOSMesa.dylib",
#endif
};
for (char const* name: libraryNames) {
g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
if (g_driver.library) {
break;
}
}
if (!g_driver.library) {
// The library has been linked explicitly during compile.
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
} else {
if (g_driver.library) {
// Linking against a libosmesa.so.
g_driver.OSMesaGetProcAddress =
(ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress");
}
#if defined(__linux__)
else {
// If Filament was built as a dynamic library.
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
}
if (!g_driver.OSMesaGetProcAddress) {
// If statically linking OSMesa.
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) OSMesaGetProcAddress;
}
#endif
return g_driver.OSMesaGetProcAddress;
}
+1 -1
View File
@@ -12,7 +12,7 @@
## Capabilities
fgviewer is a library and web application for real-time visualization of the frame graph in Filament.
fgviewer is a library and web application for real-time visualization of the frame graph in Filament.
It displays active passes and resource usage, providing insights into the rendering pipeline.
## Setup for Desktop
@@ -58,7 +58,7 @@ public:
utils::CString name;
utils::CString value;
};
Resource(ResourceId id, utils::CString name,
std::vector<Property> properties);
+8
View File
@@ -17,14 +17,22 @@
#include "ApiHandler.h"
#include <__chrono/duration.h>
#include <fgviewer/DebugServer.h>
#include <fgviewer/JsonWriter.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <CivetServer.h>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <string>
namespace filament::fgviewer {
using namespace std::chrono_literals;
+12 -3
View File
@@ -21,36 +21,45 @@
#include <CivetServer.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Hash.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
#include <utils/ostream.h>
#include <mutex>
#include <string>
#include <string_view>
namespace filament::fgviewer {
// If set to 0, this serves HTML from a resgen resource. Use 1 only during local development, which
// serves files directly from the source code tree.
#define SERVE_FROM_SOURCE_TREE 0
#if SERVE_FROM_SOURCE_TREE
namespace {
std::string const BASE_URL = "libs/fgviewer/web";
} // anonymous
#else
#include "fgviewer_resources.h"
#include <unordered_map>
namespace {
struct Asset {
std::string_view mime;
std::string_view data;
};
std::unordered_map<std::string_view, Asset> ASSET_MAP;
} // anonymous
#endif // SERVE_FROM_SOURCE_TREE
namespace filament::fgviewer {
using namespace utils;
std::string_view const DebugServer::kSuccessHeader =
+5
View File
@@ -16,6 +16,11 @@
#include <fgviewer/FrameGraphInfo.h>
#include <utils/CString.h>
#include <unordered_map>
#include <vector>
namespace filament::fgviewer {
FrameGraphInfo::FrameGraphInfo(utils::CString viewName):
+6 -2
View File
@@ -14,11 +14,15 @@
* limitations under the License.
*/
#include <fgviewer/JsonWriter.h>
#include <fgviewer/FrameGraphInfo.h>
#include <fgviewer/JsonWriter.h>
#include <iomanip>
#include <utils/CString.h>
#include <cstddef>
#include <ostream>
#include <sstream>
#include <vector>
namespace filament::fgviewer {
+8 -8
View File
@@ -223,8 +223,8 @@ class FrameGraphSidePanel extends LitElement {
return html`
<menu-section title="${title}">
${this.framegraphs.map(({ fgid, name }) => html`
<div class="framegraph"
@click="${() => this._handleFrameGraphClick(fgid)}"
<div class="framegraph"
@click="${() => this._handleFrameGraphClick(fgid)}"
data-id="${fgid}">
${fgid === this.selectedFrameGraph ? '● ' : ''}${name}
</div>
@@ -440,15 +440,15 @@ class FrameGraphTable extends LitElement {
return html`
<tr id="resource-${resourceIndex}">
<th class="sticky-col resource ${selectedStyle}" @click="${onClickResource}">
${hasSubresources
${hasSubresources
? html`
<span class="toggle-icon"
@click="${(e) => { e.stopPropagation(); this._toggleCollapse(resourceIndex); }}">
${isExpanded ? '▼' : '▶'}
</span>`
</span>`
: nothing}
${resource.name}
${hasSubresources && isExpanded ? nothing : html`(${subresourceIds.length})`}
${hasSubresources && !isExpanded ? html`(${subresourceIds.length})` : nothing}
</th>
${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)}
</tr>
@@ -592,12 +592,12 @@ class FrameGraphViewer extends LitElement {
return html`
<framegraph-sidepanel id="sidepanel"
?connected="${this.connected}"
selected-framegraph="${this.selectedFrameGraph}"
selected-framegraph="${this.selectedFrameGraph}"
selected-resource="${this.selectedResourceId}">
</framegraph-sidepanel>
<framegraph-table id="table"
<framegraph-table id="table"
?connected="${this.connected}"
selected-framegraph="${this.selectedFrameGraph}"
selected-framegraph="${this.selectedFrameGraph}"
selected-resource="${this.selectedResourceId}">
</framegraph-table>
`;
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 57;
static constexpr size_t MATERIAL_VERSION = 58;
/**
* Supported shading models
@@ -203,7 +203,7 @@ enum class ReflectionMode : uint8_t {
// can't really use std::underlying_type<AttributeIndex>::type because the driver takes a uint32_t
using AttributeBitset = utils::bitset32;
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 29;
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 30;
enum class Property : uint8_t {
BASE_COLOR, //!< float4, all shading models
ROUGHNESS, //!< float, lit shading models only
@@ -234,6 +234,7 @@ enum class Property : uint8_t {
BENT_NORMAL, //!< float3, all shading models only, except unlit
SPECULAR_FACTOR, //!< float, lit shading models only, except subsurface and cloth
SPECULAR_COLOR_FACTOR, //!< float3, lit shading models only, except subsurface and cloth
SHADOW_STRENGTH, //!< float, [0, 1] strength of shadows received by this material
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
};
@@ -217,12 +217,13 @@ public:
MaterialBuilder(MaterialBuilder&& rhs) noexcept = default;
MaterialBuilder& operator=(MaterialBuilder&& rhs) noexcept = default;
static constexpr size_t MATERIAL_VARIABLES_COUNT = 4;
static constexpr size_t MATERIAL_VARIABLES_COUNT = 5;
enum class Variable : uint8_t {
CUSTOM0,
CUSTOM1,
CUSTOM2,
CUSTOM3
CUSTOM3,
CUSTOM4, // CUSTOM4 is only available if the vertex attribute `color` is not required.
// when adding more variables, make sure to update MATERIAL_VARIABLES_COUNT
};
+2 -1
View File
@@ -49,7 +49,8 @@ std::unordered_map<std::string, Property> Enums::mStringToProperty = {
{ "microThickness", Property::MICRO_THICKNESS },
{ "bentNormal", Property::BENT_NORMAL },
{ "specularFactor", Property::SPECULAR_FACTOR },
{ "specularColorFactor", Property::SPECULAR_COLOR_FACTOR }
{ "specularColorFactor", Property::SPECULAR_COLOR_FACTOR },
{ "shadowStrength", Property::SHADOW_STRENGTH }
};
template <>
+98 -19
View File
@@ -517,29 +517,104 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
MetalArgumentBuffer::destroy(&argBuffer);
}
}
void GLSLPostProcessor::rebindImageSamplerForWGSL(std::vector<uint32_t>& spirv) {
constexpr size_t HEADER_SIZE = 5;
size_t const dataSize = spirv.size();
uint32_t* data = spirv.data();
struct Descriptor {
uint32_t binding = 0xFFFFFFFF;
bool fixed = false;
};
std::unordered_map<uint32_t, Descriptor> descriptors;
std::set<uint32_t> unidentifiedLoadTargets;
std::vector<uint32_t> bindingTargets;
auto getDesc = [&](uint32_t var) -> Descriptor& {
using itertype = std::unordered_map<uint32_t, Descriptor>::iterator;
itertype itr;
if (itr = descriptors.find(var); itr == descriptors.end()) {
itr = descriptors.insert({var, {}}).first;
}
return itr->second;
};
auto pass = [&](uint32_t targetOp, std::function<void(uint32_t)> f) {
for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) {
uint32_t const firstWord = data[cursor];
uint32_t const wordCount = firstWord >> 16;
uint32_t const op = firstWord & 0x0000FFFF;
if (targetOp == op) {
f(cursor+1);
}
cursor += wordCount;
}
};
uint32_t samplerTypeId = 0;
pass(spv::Op::OpName, [&](uint32_t pos) {
auto target = data[pos];
char* name = (char*)&data[pos+1];
std::string_view view(name);
if (view.find("_sampler") != std::string_view::npos) {
unidentifiedLoadTargets.insert(target);
}
});
// Write out the offsetted bindings
pass(spv::Op::OpDecorate, [&](uint32_t pos) {
uint32_t const type = data[pos + 1];
if (type == spv::Decoration::DecorationBinding) {
uint32_t const targetVar = data[pos];
if (unidentifiedLoadTargets.find(targetVar) != unidentifiedLoadTargets.end()) {
data[pos + 2] = data[pos + 2]*2 + 1;
}
else {
data[pos + 2] = data[pos + 2] *2;
}
}
});
}
bool GLSLPostProcessor::spirvToWgsl(SpirvBlob *spirv, std::string *outWsl) {
#if FILAMENT_SUPPORTS_WEBGPU
// We need to remove dead code for our variant-filter workaround for WebGPU to work
// This is especially relevant for removing the push constants that morphing uses when not disabled
spv::spirvbin_t remapper(0);
remapper.remap(*spirv, spv::spirvbin_base_t::DCE_ALL);
//We need to run some opt-passes at all times to transpile to WGSL
auto optimizer = createEmptyOptimizer();
optimizer->RegisterPass(CreateSplitCombinedImageSamplerPass());
//optimizer->RegisterPass(CreateResolveBindingConflictsPass());
//Currently no options we want to use
const tint::spirv::reader::Options readerOpts{};
optimizeSpirv(optimizer, *spirv);
//After splitting the image samplers, we need to remap the bindings to separate them.
//TODO: This has issues, so use CreateResolveBindingConflictsPass instead. Mapping is less predictable but short term
rebindImageSamplerForWGSL(*spirv);
//Allow non-uniform derivitives 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{};
tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts);
if (tintRead.Diagnostics().ContainsErrors()) {
//TODO remove this if block once combined image sampler conversion works.
if (tintRead.Diagnostics().Str().rfind("error: WGSL does not support combined image-samplers") != std::string::npos) {
slog.w << "This tint reader error is currently ignored during WebGPU bringup: " << tintRead.Diagnostics().Str() << io::endl;
}
else {
slog.e << "Tint Reader Error: " << tintRead.Diagnostics().Str() << io::endl;
return false;
}
//We know errors can potentially crop up, and want the ability to ignore them if needed for sample bringup
#ifndef FILAMENT_WEBGPU_IGNORE_TNT_READ_ERRORS
slog.e << "Tint Reader Error: " << tintRead.Diagnostics().Str() << io::endl;
spv_context context = spvContextCreate(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
spv_text text = nullptr;
spv_diagnostic diagnostic = nullptr;
spv_result_t result = spvBinaryToText(
context,
spirv->data(),
spirv->size(),
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_COLOR,
&text,
&diagnostic);
slog.e << "Beginning SpirV-output dump\n\n" << text->str << "\n\nEndSPIRV\n" << io::endl;
spvTextDestroy(text);
return false;
#endif
}
tint::Result<tint::wgsl::writer::Output> wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts);
@@ -887,10 +962,8 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
return true;
}
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
MaterialBuilder::Optimization optimization, Config const& config) {
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createEmptyOptimizer() {
auto optimizer = std::make_shared<spvtools::Optimizer>(SPV_ENV_UNIVERSAL_1_3);
optimizer->SetMessageConsumer([](spv_message_level_t level,
const char* source, const spv_position_t& position, const char* message) {
if (!filterSpvOptimizerMessage(level)) {
@@ -899,6 +972,12 @@ std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
slog.e << stringifySpvOptimizerMessage(level, source, position, message)
<< io::endl;
});
return optimizer;
}
std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
MaterialBuilder::Optimization optimization, Config const& config) {
auto optimizer = createEmptyOptimizer();
if (optimization == MaterialBuilder::Optimization::SIZE) {
// When optimizing for size, we don't run the SPIR-V through any size optimization passes
@@ -923,7 +1002,7 @@ std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
return optimizer;
}
void GLSLPostProcessor::optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv) const {
void GLSLPostProcessor::optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv) {
if (!optimizer->Run(spirv.data(), spirv.size(), &spirv)) {
slog.e << "SPIR-V optimizer pass failed" << io::endl;
return;
@@ -977,7 +1056,7 @@ void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer, Config c
RegisterPass(CreateWrapOpKillPass());
RegisterPass(CreateDeadBranchElimPass());
RegisterPass(CreateMergeReturnPass(), MaterialBuilder::TargetApi::METAL);
RegisterPass(CreateMergeReturnPass(), MaterialBuilder::TargetApi::METAL | MaterialBuilder::TargetApi::WEBGPU);
RegisterPass(CreateInlineExhaustivePass());
RegisterPass(CreateAggressiveDCEPass());
RegisterPass(CreatePrivateToLocalPass());
+7 -1
View File
@@ -114,14 +114,20 @@ private:
* Retrieve an optimizer instance tuned for the given optimization level and shader configuration.
*/
using OptimizerPtr = std::shared_ptr<spvtools::Optimizer>;
static OptimizerPtr createOptimizer(
MaterialBuilder::Optimization optimization,
Config const& config);
static OptimizerPtr createEmptyOptimizer();
static void registerSizePasses(spvtools::Optimizer& optimizer, Config const& config);
static void registerPerformancePasses(spvtools::Optimizer& optimizer, Config const& config);
void optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv) const;
static void optimizeSpirv(OptimizerPtr optimizer, SpirvBlob &spirv);
static void rebindImageSamplerForWGSL(std::vector<uint32_t>& spirv);
void fixupClipDistance(SpirvBlob& spirv, GLSLPostProcessor::Config const& config) const;
+11 -1
View File
@@ -252,6 +252,7 @@ MaterialBuilder& MaterialBuilder::variable(Variable v, const char* name) noexcep
case Variable::CUSTOM1:
case Variable::CUSTOM2:
case Variable::CUSTOM3:
case Variable::CUSTOM4:
assert(size_t(v) < MATERIAL_VARIABLES_COUNT);
mVariables[size_t(v)] = { CString(name), Precision::DEFAULT, false };
break;
@@ -266,6 +267,7 @@ MaterialBuilder& MaterialBuilder::variable(Variable v,
case Variable::CUSTOM1:
case Variable::CUSTOM2:
case Variable::CUSTOM3:
case Variable::CUSTOM4:
assert(size_t(v) < MATERIAL_VARIABLES_COUNT);
mVariables[size_t(v)] = { CString(name), precision, true };
break;
@@ -1049,7 +1051,6 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
switch (targetApi) {
// TODO: Handle webgpu here
case TargetApi::WEBGPU:
assert(!spirv.empty());
assert(wgsl.length() > 0);
@@ -1255,6 +1256,15 @@ error:
OutputTarget::COLOR, Precision::DEFAULT, OutputType::FLOAT4, "color");
}
if (mMaterialDomain == MaterialDomain::SURFACE) {
if (mRequiredAttributes[VertexAttribute::COLOR] &&
!mVariables[int(Variable::CUSTOM4)].name.empty()) {
// both the color attribute and the custom4 variable are present, that's not supported
slog.e << "Error: when the 'color' attribute is required 'Variable::CUSTOM4' is not supported." << io::endl;
goto error;
}
}
// TODO: maybe check MaterialDomain::COMPUTE has outputs
// Resolve all the #include directives within user code.
@@ -937,6 +937,15 @@ utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sst
std::string const constantString = std::visit(SpecializationConstantFormatter(), value);
static const char* types[] = { "int", "float", "bool" };
// Spec constants aren't fully supported in Tint,
// workaround until https://issues.chromium.org/issues/42250586 is resolved
if (mTargetApi == TargetApi::WEBGPU) {
out << "layout (constant_id = " << id << ") const "
<< types[value.index()] << " " << name << "_hack = " << constantString << ";\n"
<< types[value.index()] << " " << name << " = " << name << "_hack;\n";
return out;
}
if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) {
out << "layout (constant_id = " << id << ") const "
<< types[value.index()] << " " << name << " = " << constantString << ";\n";
@@ -1218,6 +1227,7 @@ char const* CodeGenerator::getConstantName(MaterialBuilder::Property property) n
case Property::BENT_NORMAL: return "BENT_NORMAL";
case Property::SPECULAR_FACTOR: return "SPECULAR_FACTOR";
case Property::SPECULAR_COLOR_FACTOR: return "SPECULAR_COLOR_FACTOR";
case Property::SHADOW_STRENGTH: return "SHADOW_STRENGTH";
}
}
+61
View File
@@ -696,6 +696,25 @@ TEST_F(MaterialCompiler, StaticCodeAnalyzerBentNormal) {
EXPECT_TRUE(PropertyListsMatch(expected, properties));
}
TEST_F(MaterialCompiler, StaticCodeAnalyzerShadowStrength) {
std::string fragmentCode(R"(
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.shadowStrength = 0.1;
}
)");
std::string shaderCode = shaderWithAllProperties(*jobSystem, ShaderStage::FRAGMENT,
fragmentCode);
GLSLTools glslTools;
MaterialBuilder::PropertyList properties{ false };
glslTools.findProperties(ShaderStage::FRAGMENT, shaderCode, properties);
MaterialBuilder::PropertyList expected{ false };
expected[size_t(filamat::MaterialBuilder::Property::SHADOW_STRENGTH)] = true;
EXPECT_TRUE(PropertyListsMatch(expected, properties));
}
TEST_F(MaterialCompiler, StaticCodeAnalyzerOutputFactor) {
std::string fragmentCode(R"(
void material(inout MaterialInputs material) {
@@ -759,6 +778,48 @@ TEST_F(MaterialCompiler, Uv0AndUv1) {
EXPECT_TRUE(result.isValid());
}
TEST_F(MaterialCompiler, FiveCustomVariables) {
filamat::MaterialBuilder builder;
builder.variable(MaterialBuilder::Variable::CUSTOM0, "custom0");
builder.variable(MaterialBuilder::Variable::CUSTOM1, "custom1");
builder.variable(MaterialBuilder::Variable::CUSTOM2, "custom2");
builder.variable(MaterialBuilder::Variable::CUSTOM3, "custom3");
builder.variable(MaterialBuilder::Variable::CUSTOM4, "custom4");
filamat::Package result = builder.build(*jobSystem);
EXPECT_TRUE(result.isValid());
}
TEST_F(MaterialCompiler, FourCustomVariablesAndColorAttribute) {
filamat::MaterialBuilder builder;
builder.require(filament::VertexAttribute::COLOR);
builder.variable(MaterialBuilder::Variable::CUSTOM0, "custom0");
builder.variable(MaterialBuilder::Variable::CUSTOM1, "custom1");
builder.variable(MaterialBuilder::Variable::CUSTOM2, "custom2");
builder.variable(MaterialBuilder::Variable::CUSTOM3, "custom3");
filamat::Package result = builder.build(*jobSystem);
EXPECT_TRUE(result.isValid());
}
TEST_F(MaterialCompiler, FiveCustomVariablesAndColorAttributeFails) {
filamat::MaterialBuilder builder;
builder.require(filament::VertexAttribute::COLOR);
builder.variable(MaterialBuilder::Variable::CUSTOM0, "custom0");
builder.variable(MaterialBuilder::Variable::CUSTOM1, "custom1");
builder.variable(MaterialBuilder::Variable::CUSTOM2, "custom2");
builder.variable(MaterialBuilder::Variable::CUSTOM3, "custom3");
builder.variable(MaterialBuilder::Variable::CUSTOM4, "custom4");
filamat::Package result = builder.build(*jobSystem);
EXPECT_FALSE(result.isValid());
}
TEST_F(MaterialCompiler, CustomVariable4AndColorAttributeFails) {
filamat::MaterialBuilder builder;
builder.require(filament::VertexAttribute::COLOR);
builder.variable(MaterialBuilder::Variable::CUSTOM4, "custom4");
filamat::Package result = builder.build(*jobSystem);
EXPECT_FALSE(result.isValid());
}
TEST_F(MaterialCompiler, Arrays) {
filamat::MaterialBuilder builder;
+6
View File
@@ -20,6 +20,9 @@ struct PostProcessVertexInputs {
#ifdef VARIABLE_CUSTOM3
vec4 VARIABLE_CUSTOM3;
#endif
#ifdef VARIABLE_CUSTOM4
vec4 VARIABLE_CUSTOM4;
#endif
};
void initPostProcessMaterialVertex(out PostProcessVertexInputs inputs) {
@@ -35,4 +38,7 @@ void initPostProcessMaterialVertex(out PostProcessVertexInputs inputs) {
#ifdef VARIABLE_CUSTOM3
inputs.VARIABLE_CUSTOM3 = vec4(0.0);
#endif
#ifdef VARIABLE_CUSTOM4
inputs.VARIABLE_CUSTOM4 = vec4(0.0);
#endif
}
+3
View File
@@ -39,6 +39,9 @@ void main() {
#if defined(VARIABLE_CUSTOM3)
VARIABLE_CUSTOM_AT3 = inputs.VARIABLE_CUSTOM3;
#endif
#if defined(VARIABLE_CUSTOM4)
VARIABLE_CUSTOM_AT4 = inputs.VARIABLE_CUSTOM4;
#endif
// some PowerVR drivers crash when gl_Position is written more than once
gl_Position = inputs.position;
+3 -3
View File
@@ -129,14 +129,14 @@ bool isDoubleSided() {
/**
* Returns the cascade index for this fragment (between 0 and CONFIG_MAX_SHADOW_CASCADES - 1).
*/
int getShadowCascade() {
uint getShadowCascade() {
highp float z = mulMat4x4Float3(getViewFromWorldMatrix(), getWorldPosition()).z;
ivec4 greaterZ = ivec4(greaterThan(frameUniforms.cascadeSplits, vec4(z)));
int cascadeCount = frameUniforms.cascades & 0xF;
uint cascadeCount = frameUniforms.cascades & 0xF;
return clamp(greaterZ.x + greaterZ.y + greaterZ.z + greaterZ.w, 0, cascadeCount - 1);
}
highp vec4 getCascadeLightSpacePosition(int cascade) {
highp vec4 getCascadeLightSpacePosition(uint cascade) {
// For the first cascade, return the interpolated light space position.
// This branch will be coherent (mostly) for neighboring fragments, and it's worth avoiding
// the matrix multiply inside computeLightSpacePosition.
+5 -2
View File
@@ -52,12 +52,15 @@ void evaluateDirectionalLight(const MaterialInputs material,
if (light.NoL > 0.0) {
float ssContactShadowOcclusion = 0.0;
int cascade = getShadowCascade();
uint cascade = getShadowCascade();
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1 << cascade) << 8));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
highp vec4 shadowPosition = getShadowPosition(cascade);
visibility = shadow(true, sampler0_shadowMap, cascade, shadowPosition, 0.0);
visibility = shadow(true, sampler0_shadowMap, int(cascade), shadowPosition, 0.0);
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
applyShadowStrength(visibility, material.shadowStrength);
#endif
// shadow far attenuation
highp vec3 v = getWorldPosition() - getWorldCameraPosition();
// (viewFromWorld * v).z == dot(transpose(viewFromWorld), v)
+3
View File
@@ -222,6 +222,9 @@ void evaluatePunctualLights(const MaterialInputs material,
highp vec4 shadowPosition = getShadowPosition(shadowIndex, light.direction, light.zLight);
visibility = shadow(false, sampler0_shadowMap, shadowIndex,
shadowPosition, light.zLight);
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
applyShadowStrength(visibility, material.shadowStrength);
#endif
}
if (light.contactShadows && visibility > 0.0) {
if ((object_uniforms_flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0) {
+3
View File
@@ -151,6 +151,9 @@ void main() {
#if defined(VARIABLE_CUSTOM3)
VARIABLE_CUSTOM_AT3 = material.VARIABLE_CUSTOM3;
#endif
#if defined(VARIABLE_CUSTOM4) && !defined(HAS_ATTRIBUTE_COLOR)
VARIABLE_CUSTOM_AT4 = material.VARIABLE_CUSTOM4;
#endif
// The world position can be changed by the user in materialVertex()
vertex_worldPosition.xyz = material.worldPosition.xyz;
+7
View File
@@ -98,6 +98,10 @@ struct MaterialInputs {
vec3 specularColorFactor;
#endif
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
float shadowStrength;
#endif
};
void initMaterial(out MaterialInputs material) {
@@ -195,6 +199,9 @@ void initMaterial(out MaterialInputs material) {
material.specularColorFactor = vec3(1.0);
#endif
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
material.shadowStrength = 0.0;
#endif
}
#if defined(MATERIAL_HAS_CUSTOM_SURFACE_SHADING)
+6
View File
@@ -20,6 +20,9 @@ struct MaterialVertexInputs {
#ifdef VARIABLE_CUSTOM3
vec4 VARIABLE_CUSTOM3;
#endif
#if defined(VARIABLE_CUSTOM4) && !defined(HAS_ATTRIBUTE_COLOR)
vec4 VARIABLE_CUSTOM4;
#endif
#ifdef HAS_ATTRIBUTE_TANGENTS
vec3 worldNormal;
#endif
@@ -74,6 +77,9 @@ void initMaterialVertex(out MaterialVertexInputs material) {
#endif
#ifdef VARIABLE_CUSTOM3
material.VARIABLE_CUSTOM3 = vec4(0.0);
#endif
#if defined(VARIABLE_CUSTOM4) && !defined(HAS_ATTRIBUTE_COLOR)
material.VARIABLE_CUSTOM4 = vec4(0.0);
#endif
material.worldPosition = computeWorldPosition();
#ifdef VERTEX_DOMAIN_DEVICE
+4 -1
View File
@@ -41,12 +41,15 @@ vec4 evaluateMaterial(const MaterialInputs material) {
#if defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
#if defined(VARIANT_HAS_SHADOWING)
float visibility = 1.0;
int cascade = getShadowCascade();
uint cascade = getShadowCascade();
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1 << cascade) << 8));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
highp vec4 shadowPosition = getShadowPosition(cascade);
visibility = shadow(true, sampler0_shadowMap, cascade, shadowPosition, 0.0);
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
applyShadowStrength(visibility, material.shadowStrength);
#endif
// shadow far attenuation
highp vec3 v = getWorldPosition() - getWorldCameraPosition();
// (viewFromWorld * v).z == dot(transpose(viewFromWorld), v)
+7 -1
View File
@@ -485,7 +485,7 @@ float ShadowSample_VSM(const bool ELVSM, const highp sampler2DArray shadowMap,
// get texture coordinate for directional and spot shadow maps
#if defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
highp vec4 getShadowPosition(const int cascade) {
highp vec4 getShadowPosition(const uint cascade) {
return getCascadeLightSpacePosition(cascade);
}
#endif
@@ -511,6 +511,12 @@ int getPointLightFace(const highp vec3 r) {
}
}
#if defined(MATERIAL_HAS_SHADOW_STRENGTH)
void applyShadowStrength(inout float visibility, float strength) {
visibility = 1.0 - (1.0 - visibility) * strength;
}
#endif
// PCF sampling
float shadow(const bool DIRECTIONAL,
const mediump sampler2DArrayShadow shadowMap,
+19 -19
View File
@@ -2,30 +2,30 @@
// Varyings
//------------------------------------------------------------------------------
LAYOUT_LOCATION(4) VARYING highp vec4 vertex_worldPosition;
#if defined(HAS_ATTRIBUTE_TANGENTS)
LAYOUT_LOCATION(5) SHADING_INTERPOLATION VARYING mediump vec3 vertex_worldNormal;
#if defined(MATERIAL_NEEDS_TBN)
LAYOUT_LOCATION(6) SHADING_INTERPOLATION VARYING mediump vec4 vertex_worldTangent;
#endif
#endif
LAYOUT_LOCATION(7) VARYING highp vec4 vertex_position;
#if defined(FILAMENT_HAS_FEATURE_INSTANCING)
LAYOUT_LOCATION(8) flat VARYING highp int instance_index;
highp int logical_instance_index;
#endif
#if defined(HAS_ATTRIBUTE_COLOR)
LAYOUT_LOCATION(9) VARYING mediump vec4 vertex_color;
LAYOUT_LOCATION(4) VARYING mediump vec4 vertex_color;
#endif
#if defined(HAS_ATTRIBUTE_UV0) && !defined(HAS_ATTRIBUTE_UV1)
LAYOUT_LOCATION(10) VARYING highp vec2 vertex_uv01;
LAYOUT_LOCATION(5) VARYING highp vec2 vertex_uv01;
#elif defined(HAS_ATTRIBUTE_UV1)
LAYOUT_LOCATION(10) VARYING highp vec4 vertex_uv01;
LAYOUT_LOCATION(5) VARYING highp vec4 vertex_uv01;
#endif
LAYOUT_LOCATION(6) VARYING highp vec4 vertex_worldPosition;
#if defined(HAS_ATTRIBUTE_TANGENTS)
LAYOUT_LOCATION(7) SHADING_INTERPOLATION VARYING mediump vec3 vertex_worldNormal;
#if defined(MATERIAL_NEEDS_TBN)
LAYOUT_LOCATION(8) SHADING_INTERPOLATION VARYING mediump vec4 vertex_worldTangent;
#endif
#endif
LAYOUT_LOCATION(9) VARYING highp vec4 vertex_position;
#if defined(FILAMENT_HAS_FEATURE_INSTANCING)
LAYOUT_LOCATION(10) flat VARYING highp int instance_index;
highp int logical_instance_index;
#endif
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
+6 -1
View File
@@ -46,7 +46,12 @@ def render_test(gltf_viewer, test_config, output_dir,
for backend in test_config.backends:
env = None
if backend == 'opengl' and opengl_lib and os.path.isdir(opengl_lib):
env = {'LD_LIBRARY_PATH': opengl_lib}
env = {
'LD_LIBRARY_PATH': opengl_lib,
# for macOS
'DYLD_LIBRARY_PATH': opengl_lib,
}
for model in test.models:
model_path = test_config.models[model]
+10 -2
View File
@@ -18,11 +18,19 @@ OUTPUT_DIR="$(pwd)/out/renderdiff_tests"
RENDERDIFF_TEST_DIR="$(pwd)/test/renderdiff"
TEST_UTILS_DIR="$(pwd)/test/utils"
MESA_DIR="$(pwd)/mesa/out/"
MESA_LIB_DIR="${MESA_DIR}/lib/x86_64-linux-gnu"
os_name=$(uname -s)
if [[ "$os_name" == "Linux" ]]; then
MESA_LIB_DIR="${MESA_DIR}lib/x86_64-linux-gnu"
elif [[ "$os_name" == "Darwin" ]]; then
MESA_LIB_DIR="${MESA_DIR}lib"
else
echo "Unsupported platform for renderdiff tests"
exit 1
fi
function prepare_mesa() {
if [ ! -d ${MESA_LIB_DIR} ]; then
rm -rf mesa
bash ${TEST_UTILS_DIR}/get_mesa.sh
fi
}
+2 -1
View File
@@ -8,7 +8,8 @@
"models": ["lucy", "DamagedHelmet"],
"rendering": {
"viewer.cameraFocusDistance": 0,
"view.postProcessingEnabled": true
"view.postProcessingEnabled": true,
"view.dithering": "NONE"
}
}
],
+88 -34
View File
@@ -17,55 +17,109 @@
set -xe
# GITHUB_CLANG_VERSION is set in build/linux/ci-common.sh
os_name=$(uname -s)
LLVM_VERSION=16
MESA_DIR=$(pwd)/mesa
if [[ "$GITHUB_WORKFLOW" ]]; then
# We only want to do this if it is a CI machine.
sudo apt-get -y remove llvm-*
if [[ "$os_name" == "Linux" ]]; then
if [[ "$GITHUB_WORKFLOW" ]]; then
# We only want to do this if it is a CI machine.
sudo apt-get -y remove llvm-*
# We do a manual install of dependencies instead of `apt-get -y build-dep mesa`
# because this allows us to compile an older mesa, and also because build-deps
# is constantly being updated and sometimes not compatible with the current
# linux platform.
# Note that we assume this platform is compatible with ubuntu-22.04 x86_64
sudo apt-get -y install \
autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${GITHUB_CLANG_VERSION} llvm-${GITHUB_CLANG_VERSION}-dev llvm-${GITHUB_CLANG_VERSION}-linker-tools llvm-${GITHUB_CLANG_VERSION}-runtime llvm-${GITHUB_CLANG_VERSION}-tools llvm-spirv-${GITHUB_CLANG_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \
clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
# We do a manual install of dependencies instead of `apt-get -y build-dep mesa`
# because this allows us to compile an older mesa, and also because build-deps
# is constantly being updated and sometimes not compatible with the current
# linux platform.
# Note that we assume this platform is compatible with ubuntu-22.04 x86_64
sudo apt-get -y install \
autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0f:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-linker-tools llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools llvm-spirv-${LLVM_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \
clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
else
set +e
sudo apt-get -y build-dep mesa
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
set -e
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}}
sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \
libc++-${GITHUB_CLANG_VERSION}-dev \
libc++abi-${GITHUB_CLANG_VERSION}-dev \
llvm-${LLVM_VERSION} \
llvm-${LLVM_VERSION}-{dev,tools,runtime}
fi # [[ "$GITHUB_WORKFLOW" ]]
elif [[ "$os_name" == "Darwin" ]]; then
if [[ ! "$GITHUB_WORKFLOW" ]]; then
if [ ! command -v brew > /dev/null 2>&1 ]; then
echo "Error: need to install homebrew to continue"
exit 1
fi
fi
brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
NEEDED_PYTHON_DEPS=("mako" "setuptools")
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
if ! pip3 show "${cmd}" >/dev/null 2>&1; then
sudo pip3 install ${cmd}
fi
done
fi # [[ "$os_name" == x ]]
LOCAL_LDFLAGS=${LDFLAGS}
LOCAL_CPPFLAGS=${CPPFLAGS}
LOCAL_PATH=${PATH}
LOCAL_CXX=$(which clang++)
LOCAL_CC=$(which clang)
CHECKOUT_MESA=false
if [[ -d "${MESA_DIR}" ]]; then
cd ${MESA_DIR}
if ! git fsck --connectivity-only > /dev/null 2>&1; then
echo "git fsck failed for mesa; try redownloading"
CHECKOUT_MESA=true;
fi
cd ..;
else
set +e
sudo apt-get -y build-dep mesa
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
set -e
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}}
sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \
libc++-${GITHUB_CLANG_VERSION}-dev \
libc++abi-${GITHUB_CLANG_VERSION}-dev \
llvm-${GITHUB_CLANG_VERSION} \
llvm-${GITHUB_CLANG_VERSION}-{dev,tools,runtime}
CHECKOUT_MESA=true
fi
if [[ "$CHECKOUT_MESA" = "true" ]]; then
rm -rf ${MESA_DIR}
export CXX=`which clang++` && export CC=`which clang`
git clone https://gitlab.freedesktop.org/mesa/mesa.git
#git clone https://gitlab.freedesktop.org/mesa/mesa.git
git clone git://anongit.freedesktop.org/mesa/mesa
# Due to gitlab mesa outage.
if [[ "${MESA_DIR}" != "$(pwd)/mesa" ]]; then
mv mesa ${MESA_DIR}
fi
fi
pushd .
cd ${MESA_DIR}
cd mesa
git checkout mesa-23.2.1
# Need >= 24 to have llvmpipe for swrast. llvmpipe is needed for GL >= 4.1.
git checkout mesa-24.2.1
mkdir -p out
if [[ "$os_name" == "Darwin" ]]; then
LOCAL_LDFLAGS="-L/opt/homebrew/opt/llvm@${LLVM_VERSION}/lib"
LOCAL_CPPFLAGS="-I/opt/homebrew/opt/llvm@${LLVM_VERSION}/include -I/opt/homebrew/include"
LOCAL_PATH=${PATH}:/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin
# This is necessary to be able to build vk (lavapipe) on macOS. Doesn't seem like a real dependency.
sed -I '' "s/error('Vulkan drivers require dri3 for X11 support')//g" meson.build
fi
# -Dosmesa=true => builds OSMesa, which is an offscreen GL context
# -Dgallium-drivers=swrast => builds GL software rasterizer
# -Dvulkan-drivers=swrast => builds VK software rasterizer
meson setup builddir/ -Dprefix="$(pwd)/out" -Dosmesa=true -Dglx=xlib -Dgallium-drivers=swrast -Dvulkan-drivers=swrast
meson install -C builddir/
# -Dgallium-drivers=llvmpipe is needed for GL >= 4.1 pipe-screen (see src/gallium/auxiliary/target-helpers/inline_sw_helper.h)
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson setup --wipe builddir/ -Dprefix="$(pwd)/out" -Dglx=xlib -Dosmesa=true -Dgallium-drivers=llvmpipe,swrast -Dvulkan-drivers=swrast
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson install -C builddir/
popd
+2
View File
@@ -172,11 +172,13 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/remove_unused_interface_variables_pass.cpp \
source/opt/replace_desc_array_access_using_var_index.cpp \
source/opt/replace_invalid_opc.cpp \
source/opt/resolve_binding_conflicts_pass.cpp \
source/opt/scalar_analysis.cpp \
source/opt/scalar_analysis_simplification.cpp \
source/opt/scalar_replacement_pass.cpp \
source/opt/set_spec_constant_default_value_pass.cpp \
source/opt/simplification_pass.cpp \
source/opt/split_combined_image_sampler_pass.cpp \
source/opt/spread_volatile_semantics.cpp \
source/opt/ssa_rewrite_pass.cpp \
source/opt/strength_reduction_pass.cpp \
+1
View File
@@ -201,6 +201,7 @@ cc_library(
deps = [
":spirv_tools_internal",
"@spirv_headers//:spirv_common_headers",
"@spirv_headers//:spirv_c_headers",
],
)
+5
View File
@@ -771,6 +771,8 @@ static_library("spvtools_opt") {
"source/opt/replace_desc_array_access_using_var_index.h",
"source/opt/replace_invalid_opc.cpp",
"source/opt/replace_invalid_opc.h",
"source/opt/resolve_binding_conflicts_pass.cpp",
"source/opt/resolve_binding_conflicts_pass.h",
"source/opt/scalar_analysis.cpp",
"source/opt/scalar_analysis.h",
"source/opt/scalar_analysis_nodes.h",
@@ -781,6 +783,8 @@ static_library("spvtools_opt") {
"source/opt/set_spec_constant_default_value_pass.h",
"source/opt/simplification_pass.cpp",
"source/opt/simplification_pass.h",
"source/opt/split_combined_image_sampler_pass.cpp",
"source/opt/split_combined_image_sampler_pass.h",
"source/opt/spread_volatile_semantics.cpp",
"source/opt/spread_volatile_semantics.h",
"source/opt/ssa_rewrite_pass.cpp",
@@ -1382,6 +1386,7 @@ if (build_with_chromium && spvtools_build_executables) {
"test/libspirv_macros_test.cpp",
"test/name_mapper_test.cpp",
"test/named_id_test.cpp",
"test/op_unknown_test.cpp",
"test/opcode_make_test.cpp",
"test/opcode_require_capabilities_test.cpp",
"test/opcode_split_test.cpp",
+35
View File
@@ -1,5 +1,40 @@
Revision history for SPIRV-Tools
v2025.1 2025-02-28
- General
- diff: Fix crash in OpString matching (#5988)
- Add SPV_AMDX_shader_enqueue version 2 support (#5838)
- add support for SPV_INTEL_subgroup_matrix_multiply_accumulate (#5928)
- update cmake_minimum_required to 3.22.1 (#5925)
- Add OpImageSampleFootprintNV to IsAllowedSampledImageOperand (#5914)
- assembler: ensure progress when seeking the version string (#5910)
- Optimizer
- opt: keep all OpSource instructions (#5901)
- [opt] Fix bug opt::InstructionBuilder::AddVariable (#6007)
- [OPT] Add SPV_KHR_ray_tracing to allow list (#5941)
- opt: keep all OpSource instructions (#5901)
- Validator
- spirv-val: Add AllowVulkan32BitBitwise option (#6001)
- Fix untyped pointer comparison validation (#6004)
- spirv-val: Update VUIDs for 308 header (#5990)
- spirv-val: fix env parsing for vk1.1spv1.4 (#5985)
- Add validation for SPV_NV_linear_swept_spheres. (#5975)
- Add validation SPV_NV_cluster_acceleration_structure. (#5974)
- Improve the instruction diagnostic for some access chain errors (#5978)
- Update physical storage buffer validation to match SPIR-V 1.6.5 (#5977)
- Validate SPV_NV_cooperative_vector (#5972)
- Fix layout checks with untyped pointers (#5970)
- spirv-val: Update mislabeled VUIDs (#5964)
- More explicit layout validation (#5958)
- spirv-val: Add VK_KHR_maintenance8 support (#5951)
- Add EXT_mesh_shader validation support (#5640)
- spirv-val: Remove OpenCL ivec3 req (#5940)
- spirv-val: Validate zero product workgroup size (#5407)
- Relax DebugLine validation (#5916)
- Linker
- linker: remove LinkOnceODR decorations when linking executables (#5979)
- fix: handle LinkOnceODR correctly (#5938)
v2024.4 2024-12-04
- General
- Add FPEncoding operand type. (#5726)
+5 -5
View File
@@ -3,18 +3,18 @@ use_relative_paths = True
vars = {
'github': 'https://github.com',
'abseil_revision': '69b58f9227bf91a9315475579df15fbb7c5c612e',
'abseil_revision': '9f5fc9d1e934571a1f713b5a00cd5f15db8c71ed',
'effcee_revision': '12241cbc30f20730b656db7fd5a3fa36cd420843',
'effcee_revision': '874b47102c57a8979c0f154cf8e0eab53c0a0502',
'googletest_revision': 'e235eb34c6c4fed790ccdad4b16394301360dcd4',
'googletest_revision': '3af834740f58ef56058e6f8a1be51f62bc3a6515',
# Use protobufs before they gained the dependency on abseil
'protobuf_revision': 'v21.12',
're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca',
're2_revision': 'c84a140c93352cdabbfb547c531be34515b12228',
'spirv_headers_revision': 'e7294a8ebed84f8c5bd3686c68dbe12a4e65b644',
'spirv_headers_revision': '0e710677989b4326ac974fd80c5308191ed80965',
}
deps = {
+44
View File
@@ -215,6 +215,50 @@ Note that this has some interesting consequences, including:
that named ID being output. This may be valid SPIR-V, contrary to the
presumed intention of the writer.
## OpUnknown
<a name="op-unknown"></a>
HLSL has a feature that allows users to specify an exact SPIR-V type using [the
`SpirvType` template](https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md#types).
This feature allows the user to specify a type opcode that the compiler does
not know. In this case, it will be unable to generate assembly using the
correct mnemonic.
In order to represent unknown opcodes in assembly format, the `OpUnknown`
pseudo-instruction may be used. The syntax is:
```
OpUnknown(<enumerant>, <WordCount>) <operand 1> ...
```
`enumerant` is the opcode enumerant, and `WordCount` is the number of words in
the instruction. These will be assembled into a single word representing the
opcode. Operands will be parsed according to the alternate parsing mode
described in [Arbitrary Integers](#op-unknown). Named enumerated values cannot
be handled by this mode and must be represented using the arbitrary integer
syntax.
It must be used at the beginning of a new instruction, and if there is a result
ID it must explicitly be passed in as an operand. This is because the physical
layout of a SPIR-V instruction may include a result type operand before the
result ID operand, but it depends on the opcode and cannot be inferred for an
unknown operand.
For example, a 32-bit signed integer type could be represented like this:
```
OpUnknown(21, 4) %int_t 32 1
```
An OpStore instruction could be represented as:
```
OpUnknown(62, 3) %9 %12
```
The enumerant and word count must be decimal integers.
## Notes
* Some enumerants cannot be used by name, because the target instruction
@@ -740,6 +740,10 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetAllowLocalSizeId(
SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetAllowOffsetTextureOperand(
spv_validator_options options, bool val);
// Allow base operands of some bit operations to be non-32-bit wide.
SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetAllowVulkan32BitBitwise(
spv_validator_options options, bool val);
// Whether friendly names should be used in validation error messages.
SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetFriendlyNames(
spv_validator_options options, bool val);
@@ -132,6 +132,11 @@ class SPIRV_TOOLS_EXPORT ValidatorOptions {
spvValidatorOptionsSetAllowOffsetTextureOperand(options_, val);
}
// Allow base operands of some bit operations to be non-32-bit wide.
void SetAllowVulkan32BitBitwise(bool val) {
spvValidatorOptionsSetAllowVulkan32BitBitwise(options_, val);
}
// Records whether or not the validator should relax the rules on pointer
// usage in logical addressing mode.
//

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