Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad42ee66b1 | ||
|
|
b2e77d6847 | ||
|
|
784b1650c3 |
@@ -12,7 +12,7 @@ jobs:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-32core'
|
||||
runs-on: ubuntu-22.04-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
validate-docs:
|
||||
name: validate-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
runs-on: ubuntu-22.04-4core
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -92,33 +92,27 @@ jobs:
|
||||
|
||||
test-renderdiff:
|
||||
name: test-renderdiff
|
||||
runs-on: macos-14-xlarge
|
||||
runs-on: ubuntu-22.04-4core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- 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
|
||||
- uses: ./.github/actions/ubuntu-apt-add-src
|
||||
- name: Run script
|
||||
run: |
|
||||
bash test/renderdiff/test.sh
|
||||
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
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
path: ./out/renderdiff_tests
|
||||
|
||||
validate-wgsl-webgpu:
|
||||
name: validate-wgsl-webgpu
|
||||
runs-on: 'ubuntu-24.04-8core'
|
||||
validate-wgsl-pipeline:
|
||||
name: validate-wgsl-pipeline
|
||||
runs-on: ubuntu-22.04-4core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat
|
||||
- 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*
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
||||
|
||||
steps:
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
|
||||
|
||||
steps:
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
jobs:
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
+7
-13
@@ -139,14 +139,14 @@ else()
|
||||
set(LINUX FALSE)
|
||||
endif()
|
||||
|
||||
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 (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 (FILAMENT_SUPPORTS_WAYLAND)
|
||||
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
|
||||
set(FILAMENT_SUPPORTS_X11 FALSE)
|
||||
@@ -184,12 +184,6 @@ 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
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.59.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.58.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.59.0'
|
||||
pod 'Filament', '~> 1.58.0'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,14 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.59.0
|
||||
|
||||
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
|
||||
|
||||
## v1.58.2
|
||||
|
||||
- engine: Generate 1D instead of 3D LUTs for color grading whenever possible.
|
||||
|
||||
## v1.58.1
|
||||
|
||||
|
||||
|
||||
+4
-10
@@ -46,8 +46,9 @@ 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 LUT may
|
||||
* need to be generated. The generation of this LUT, if necessary, may happen on the CPU.
|
||||
* 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.
|
||||
*
|
||||
* <h1>Ordering</h1>
|
||||
*
|
||||
@@ -159,10 +160,6 @@ 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
|
||||
@@ -178,8 +175,6 @@ 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.
|
||||
@@ -195,8 +190,6 @@ 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.
|
||||
@@ -623,3 +616,4 @@ public class ColorGrading {
|
||||
|
||||
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ 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,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.59.0
|
||||
VERSION_NAME=1.58.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -200,9 +200,8 @@ WEBGPU_ANDROID_GRADLE_OPTION=""
|
||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
||||
|
||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
||||
MATDBG_GRADLE_OPTION=""
|
||||
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
|
||||
FGVIEWER_GRADLE_OPTION=""
|
||||
MATDBG_GRADLE_OPTION=""
|
||||
|
||||
MATOPT_OPTION=""
|
||||
MATOPT_GRADLE_OPTION=""
|
||||
@@ -534,7 +533,6 @@ 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 \
|
||||
@@ -586,7 +584,6 @@ 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 \
|
||||
|
||||
@@ -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 libx11-xcb-dev
|
||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-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
|
||||
|
||||
+16
-24
@@ -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), [@pixelflinger](https://bsky.app/profile/pixelflinger.bsky.social)
|
||||
- [Mathias Agopian](https://github.com/pixelflinger), [@darthmoosious](https://twitter.com/darthmoosious)
|
||||
|
||||
# Overview
|
||||
|
||||
@@ -78,27 +78,26 @@ in table [standardProperties].
|
||||
Property | Definition
|
||||
-----------------------:|:---------------------
|
||||
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
|
||||
**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)
|
||||
**roughness** | Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
|
||||
**reflectance** | Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
|
||||
**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
|
||||
**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
|
||||
**clearCoat** | Strength of the clear coat layer
|
||||
**clearCoatRoughness** | Perceived smoothness or roughness of the clear coat layer
|
||||
**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_)
|
||||
**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
|
||||
**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
|
||||
[Table [standardProperties]: Properties of the standard model]
|
||||
|
||||
The type and range of each property is described in table [standardPropertiesTypes].
|
||||
@@ -1273,9 +1272,6 @@ 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 : [
|
||||
@@ -1306,7 +1302,7 @@ Type
|
||||
: array of `string`
|
||||
|
||||
Value
|
||||
: Up to 5 strings, each must be a valid GLSL identifier.
|
||||
: Up to 4 strings, each must be a valid GLSL identifier.
|
||||
|
||||
Description
|
||||
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
||||
@@ -1322,10 +1318,6 @@ 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,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -108,12 +108,8 @@ 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)
|
||||
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()
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
||||
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
|
||||
elseif (WEBGL)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
||||
elseif (LINUX)
|
||||
@@ -177,12 +173,10 @@ endif()
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/VulkanPlatform.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/caching/VulkanDescriptorSetManager.cpp
|
||||
src/vulkan/caching/VulkanDescriptorSetManager.h
|
||||
src/vulkan/caching/VulkanPipelineLayoutCache.cpp
|
||||
src/vulkan/caching/VulkanPipelineLayoutCache.h
|
||||
src/vulkan/memory/ResourceManager.cpp
|
||||
src/vulkan/memory/ResourceManager.h
|
||||
src/vulkan/memory/ResourcePointer.h
|
||||
@@ -422,12 +416,9 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS
|
||||
-Wl,--exclude-libs,bluegl
|
||||
)
|
||||
|
||||
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()
|
||||
if (LINUX AND FILAMENT_SUPPORTS_OSMESA)
|
||||
set(OSMESA_COMPILE_FLAGS
|
||||
-I${FILAMENT_OSMESA_PATH}/include/GL)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
@@ -494,9 +485,7 @@ if (APPLE OR LINUX)
|
||||
test/ShaderGenerator.cpp
|
||||
test/TrianglePrimitive.cpp
|
||||
test/Arguments.cpp
|
||||
test/ImageExpectations.cpp
|
||||
test/Lifetimes.cpp
|
||||
test/Shader.cpp
|
||||
test/test_FeedbackLoops.cpp
|
||||
test/test_Blit.cpp
|
||||
test/test_MissingRequiredAttributes.cpp
|
||||
@@ -512,7 +501,6 @@ if (APPLE OR LINUX)
|
||||
test/test_Handles.cpp
|
||||
)
|
||||
set(BACKEND_TEST_LIBS
|
||||
absl::str_format
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
@@ -528,7 +516,7 @@ if (APPLE AND NOT IOS)
|
||||
list(APPEND BACKEND_TEST_SRC
|
||||
test/test_RenderExternalImage.cpp)
|
||||
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
||||
target_link_libraries(backend_test PRIVATE ${BACKEND_TEST_LIBS})
|
||||
|
||||
set(BACKEND_TEST_DEPS
|
||||
OSDependent
|
||||
|
||||
@@ -256,18 +256,16 @@ struct DescriptorSetLayoutBinding {
|
||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||
uint16_t count = 0;
|
||||
|
||||
// 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;
|
||||
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.stageFlags == rhs.stageFlags &&
|
||||
// lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
||||
lhs.stageFlags == rhs.stageFlags &&
|
||||
lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1140,9 +1138,7 @@ static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
|
||||
// TODO: uncomment when needed
|
||||
// utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
||||
utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
||||
};
|
||||
|
||||
//! blending equation function
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
PlatformCocoaGL();
|
||||
~PlatformCocoaGL() noexcept override;
|
||||
|
||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
||||
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||
|
||||
protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
PlatformCocoaTouchGL();
|
||||
~PlatformCocoaTouchGL() noexcept override;
|
||||
|
||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
||||
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Platform Interface
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
/**
|
||||
* Creates an ExternalImage from a EGLImageKHR
|
||||
*/
|
||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(EGLImageKHR eglImage) noexcept;
|
||||
ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept;
|
||||
|
||||
protected:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <backend/platforms/PlatformEGL.h>
|
||||
|
||||
#include <utils/android/PerformanceHintManager.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -44,21 +43,8 @@ public:
|
||||
PlatformEGLAndroid() noexcept;
|
||||
~PlatformEGLAndroid() noexcept override;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -71,6 +57,11 @@ 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
|
||||
|
||||
@@ -104,26 +95,15 @@ protected:
|
||||
*/
|
||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
||||
|
||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
||||
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
|
||||
bool setExternalImage(ExternalImageHandleRef externalImage, 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,12 +21,7 @@
|
||||
|
||||
#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,16 +368,8 @@ 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:
|
||||
// Platform dependent helper methods
|
||||
static ExtensionSet getSwapchainInstanceExtensionsImpl();
|
||||
static ExtensionSet getSwapchainInstanceExtensions();
|
||||
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||
VkDevice device);
|
||||
@@ -394,7 +386,8 @@ private:
|
||||
VkComponentMapping swizzle);
|
||||
|
||||
// Platform dependent helper methods
|
||||
static SurfaceBundle createVkSurfaceKHRImpl(void* nativeWindow, VkInstance instance,
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance,
|
||||
uint64_t flags) noexcept;
|
||||
|
||||
friend struct VulkanPlatformPrivate;
|
||||
|
||||
@@ -17,55 +17,27 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend {
|
||||
namespace filament::backend::fvkandroid {
|
||||
|
||||
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;
|
||||
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:
|
||||
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;
|
||||
~ExternalImageVulkanAndroid() override;
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept;
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
} // namespace filament::backend::fvkandroid
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
|
||||
@@ -19,11 +19,6 @@
|
||||
#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)
|
||||
@@ -35,11 +30,7 @@
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
||||
#include <backend/platforms/PlatformOSMesa.h>
|
||||
#else
|
||||
#include <backend/platforms/PlatformCocoaGL.h>
|
||||
#endif
|
||||
#include <backend/platforms/PlatformCocoaGL.h>
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_X11)
|
||||
@@ -64,11 +55,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#if defined(__ANDROID__)
|
||||
#include "backend/platforms/VulkanPlatformAndroid.h"
|
||||
#else
|
||||
#include "backend/platforms/VulkanPlatform.h"
|
||||
#endif
|
||||
#include "backend/platforms/VulkanPlatform.h"
|
||||
#endif
|
||||
|
||||
#if defined (FILAMENT_SUPPORTS_METAL)
|
||||
@@ -78,6 +65,9 @@ filament::backend::Platform* createDefaultMetalPlatform();
|
||||
#endif
|
||||
|
||||
#include "noop/PlatformNoop.h"
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
#include "backend/platforms/WebGPUPlatform.h"
|
||||
#endif
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -114,11 +104,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
}
|
||||
if (*backend == Backend::VULKAN) {
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#if defined(__ANDROID__)
|
||||
return new VulkanPlatformAndroid();
|
||||
#else
|
||||
return new VulkanPlatform();
|
||||
#endif
|
||||
return new VulkanPlatform();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
@@ -146,11 +132,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
#elif defined(FILAMENT_IOS)
|
||||
return new PlatformCocoaTouchGL();
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
||||
return new PlatformOSMesa();
|
||||
#else
|
||||
return new PlatformCocoaGL();
|
||||
#endif
|
||||
return new PlatformCocoaGL();
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_X11)
|
||||
return new PlatformGLX();
|
||||
|
||||
@@ -1177,17 +1177,9 @@ size_t MetalDriver::getMaxUniformBufferSize() {
|
||||
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
||||
}
|
||||
|
||||
size_t MetalDriver::getMaxTextureSize(SamplerType type) {
|
||||
if (type == SamplerType::SAMPLER_3D) {
|
||||
return 2048;
|
||||
}
|
||||
if (mContext->highestSupportedGpuFamily.apple >= 3 ||
|
||||
mContext->highestSupportedGpuFamily.mac >= 2) {
|
||||
return 16384;
|
||||
} else if (mContext->highestSupportedGpuFamily.apple >= 2) {
|
||||
return 8192;
|
||||
}
|
||||
return 4096;
|
||||
size_t MetalDriver::getMaxTextureSize(SamplerType) {
|
||||
// TODO: return the actual size instead of hardcoding the minspec
|
||||
return 2048;
|
||||
}
|
||||
|
||||
size_t MetalDriver::getMaxArrayTextureLayers() {
|
||||
|
||||
@@ -241,9 +241,7 @@ size_t NoopDriver::getMaxUniformBufferSize() {
|
||||
}
|
||||
|
||||
size_t NoopDriver::getMaxTextureSize(SamplerType target) {
|
||||
// NoopDriver is being actively used for other purposes. This needs to be resolved before we
|
||||
// can change it to 2048. b/406832484
|
||||
return 16384u;
|
||||
return 2048u;
|
||||
}
|
||||
|
||||
size_t NoopDriver::getMaxArrayTextureLayers() {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* PlatformNoop::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
Driver* PlatformNoop::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
return NoopDriver::create();
|
||||
}
|
||||
|
||||
|
||||
@@ -566,11 +566,7 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
} else if (strstr(renderer, "AMD") ||
|
||||
strstr(renderer, "ATI")) {
|
||||
// AMD/ATI GPU
|
||||
} else if (strstr(renderer, "Mozilla")) {
|
||||
bugs->disable_invalidate_framebuffer = true;
|
||||
}
|
||||
|
||||
if (strstr(vendor, "Mesa")) {
|
||||
} else if (strstr(vendor, "Mesa")) {
|
||||
// Seen on
|
||||
// [Mesa],
|
||||
// [llvmpipe (LLVM 17.0.6, 256 bits)],
|
||||
@@ -578,6 +574,8 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
// [4.50]
|
||||
// not known which version are affected
|
||||
bugs->rebind_buffer_after_deletion = true;
|
||||
} else if (strstr(renderer, "Mozilla")) {
|
||||
bugs->disable_invalidate_framebuffer = true;
|
||||
}
|
||||
} else {
|
||||
// When running under ANGLE, it's a different set of workaround that we need.
|
||||
@@ -589,19 +587,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(vendor, "Mozilla")) {
|
||||
// Seen on
|
||||
// [Mozilla],
|
||||
// [GeForce GTX 980, or similar]
|
||||
// or [ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar]
|
||||
// or anything else,
|
||||
// [OpenGL ES 3.0 (WebGL 2.0)],
|
||||
// [OpenGL ES GLSL ES 3.00 (WebGL GLSL ES 3.00)]
|
||||
// For Mozilla, the issue appears to be observed regardless of whether the renderer is
|
||||
// ANGLE or not. (b/376125497)
|
||||
bugs->rebind_buffer_after_deletion = true;
|
||||
}
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
# ifndef FILAMENT_IOS // FILAMENT_IOS is guaranteed to have ES3.x
|
||||
if (UTILS_UNLIKELY(major == 2)) {
|
||||
|
||||
@@ -320,8 +320,8 @@ public:
|
||||
// a glFinish. So we must delay the destruction until we know the GPU is finished.
|
||||
bool delay_fbo_destruction;
|
||||
|
||||
// Mesa and Mozilla(web) sometimes clear the generic buffer binding when *another* buffer
|
||||
// is destroyed, if that other buffer is bound on an *indexed* buffer binding.
|
||||
// Mesa sometimes clears the generic buffer binding when *another* buffer is destroyed,
|
||||
// if that other buffer is bound on an *indexed* buffer binding.
|
||||
bool rebind_buffer_after_deletion;
|
||||
|
||||
// Force feature level 0. Typically used for low end ES3 devices with significant driver
|
||||
|
||||
@@ -148,8 +148,8 @@ using namespace utils;
|
||||
namespace filament::backend {
|
||||
|
||||
Driver* OpenGLDriverFactory::create(
|
||||
OpenGLPlatform* platform,
|
||||
void* sharedGLContext,
|
||||
OpenGLPlatform* const platform,
|
||||
void* const 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* platform,
|
||||
void* /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
||||
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
assert_invariant(platform);
|
||||
OpenGLPlatform* ec = platform;
|
||||
OpenGLPlatform* const ec = platform;
|
||||
|
||||
#if 0
|
||||
// this is useful for development, but too verbose even for debug builds
|
||||
@@ -230,7 +230,7 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* 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* driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
||||
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
||||
return driver;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
Driver* PlatformCocoaTouchGL::createDriver(void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
Driver* PlatformCocoaTouchGL::createDriver(void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
|
||||
|
||||
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <backend/platforms/PlatformEGL.h>
|
||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
||||
|
||||
#include <private/backend/BackendUtilsAndroid.h>
|
||||
#include <private/backend/VirtualMachineEnv.h>
|
||||
|
||||
#include "opengl/GLUtils.h"
|
||||
@@ -35,8 +34,6 @@
|
||||
#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>
|
||||
@@ -234,133 +231,26 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
||||
return driver;
|
||||
}
|
||||
|
||||
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
if (aHardwareBuffer) {
|
||||
AHardwareBuffer_release(aHardwareBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default;
|
||||
|
||||
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;
|
||||
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 };
|
||||
}
|
||||
|
||||
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) {
|
||||
return PlatformEGLAndroid::setImage(eglExternalImage, texture);
|
||||
// TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer
|
||||
return true;
|
||||
}
|
||||
// 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* sharedGLContext,
|
||||
Driver* PlatformGLX::createDriver(void* const sharedGLContext,
|
||||
const DriverConfig& driverConfig) noexcept {
|
||||
loadLibraries();
|
||||
// Get the display device
|
||||
|
||||
@@ -22,11 +22,9 @@
|
||||
#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 {
|
||||
|
||||
@@ -50,27 +48,20 @@ struct OSMesaSwapchain {
|
||||
|
||||
struct OSMesaAPI {
|
||||
private:
|
||||
using CreateContextAttribsFunc = OSMesaContext (*)(const int *, OSMesaContext);
|
||||
using CreateContextFunc = OSMesaContext (*)(GLenum format, 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:
|
||||
CreateContextAttribsFunc fOSMesaCreateContextAttribs;
|
||||
CreateContextFunc fOSMesaCreateContext;
|
||||
DestroyContextFunc fOSMesaDestroyContext;
|
||||
MakeCurrentFunc fOSMesaMakeCurrent;
|
||||
GetProcAddressFunc fOSMesaGetProcAddress;
|
||||
|
||||
OSMesaAPI() {
|
||||
static constexpr char const* libraryNames[] = {
|
||||
#if defined(__linux__)
|
||||
"libOSMesa.so",
|
||||
"libosmesa.so",
|
||||
#elif defined(__APPLE__)
|
||||
"libOSMesa.dylib",
|
||||
#endif
|
||||
};
|
||||
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||
for (char const* libName: libraryNames) {
|
||||
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
|
||||
if (mLib) {
|
||||
@@ -80,24 +71,22 @@ public:
|
||||
if (mLib) {
|
||||
// Loading from a libosmesa.os
|
||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
}
|
||||
#if defined(__linux__)
|
||||
else {
|
||||
} 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";
|
||||
|
||||
fOSMesaCreateContextAttribs =
|
||||
(CreateContextAttribsFunc) fOSMesaGetProcAddress("OSMesaCreateContextAttribs");
|
||||
fOSMesaDestroyContext = (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
|
||||
fOSMesaDestroyContext =
|
||||
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||
}
|
||||
|
||||
@@ -112,24 +101,14 @@ private:
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
Driver* PlatformOSMesa::createDriver(void* sharedGLContext,
|
||||
Driver* PlatformOSMesa::createDriver(void* const 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->fOSMesaCreateContextAttribs(attribs, NULL);
|
||||
mContext = api->fOSMesaCreateContext(GL_RGBA, 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* sharedGLContext,
|
||||
Driver* PlatformWGL::createDriver(void* const 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* sharedGLContext,
|
||||
Driver* PlatformWebGL::createDriver(void* const sharedGLContext,
|
||||
const Platform::DriverConfig& driverConfig) noexcept {
|
||||
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "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
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_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
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "VulkanDriver.h"
|
||||
|
||||
#include "CommandStreamDispatcher.h"
|
||||
#include "DataReshaper.h"
|
||||
#include "SystraceProfile.h"
|
||||
#include "VulkanAsyncHandles.h"
|
||||
#include "VulkanBuffer.h"
|
||||
@@ -34,6 +35,7 @@
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -42,6 +44,8 @@
|
||||
|
||||
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.
|
||||
@@ -215,8 +219,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
|
||||
mSamplerCache(mPlatform->getDevice()),
|
||||
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
||||
mReadPixels(mPlatform->getDevice()),
|
||||
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
||||
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
||||
mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager),
|
||||
mQueryManager(mPlatform->getDevice()),
|
||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||
@@ -326,8 +329,7 @@ void VulkanDriver::terminate() {
|
||||
mPipelineCache.terminate();
|
||||
mFramebufferCache.reset();
|
||||
mSamplerCache.terminate();
|
||||
mDescriptorSetLayoutCache.terminate();
|
||||
mDescriptorSetCache.terminate();
|
||||
mDescriptorSetManager.terminate();
|
||||
mPipelineLayoutCache.terminate();
|
||||
|
||||
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
|
||||
@@ -363,7 +365,7 @@ void VulkanDriver::collectGarbage() {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
// Command buffers need to be submitted and completed before other resources can be gc'd.
|
||||
mCommands.gc();
|
||||
mDescriptorSetCache.clearHistory();
|
||||
mDescriptorSetManager.clearHistory();
|
||||
mStagePool.gc();
|
||||
mFramebufferCache.gc();
|
||||
mPipelineCache.gc();
|
||||
@@ -406,7 +408,7 @@ void VulkanDriver::updateDescriptorSetBuffer(
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||
auto buffer = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
||||
mDescriptorSetCache.updateBuffer(set, binding, buffer, offset, size);
|
||||
mDescriptorSetManager.updateBuffer(set, binding, buffer, offset, size);
|
||||
}
|
||||
|
||||
void VulkanDriver::updateDescriptorSetTexture(
|
||||
@@ -419,7 +421,7 @@ void VulkanDriver::updateDescriptorSetTexture(
|
||||
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
||||
|
||||
VkSampler const vksampler = mSamplerCache.getSampler(params);
|
||||
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
|
||||
mDescriptorSetManager.updateSampler(set, binding, texture, vksampler);
|
||||
}
|
||||
|
||||
void VulkanDriver::flush(int) {
|
||||
@@ -776,7 +778,8 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
|
||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||
backend::DescriptorSetLayout&& info) {
|
||||
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
|
||||
auto layout = resource_ptr<VulkanDescriptorSetLayout>::make(&mResourceManager, dslh, info);
|
||||
mDescriptorSetManager.initVkLayout(layout);
|
||||
layout.inc();
|
||||
}
|
||||
|
||||
@@ -785,7 +788,7 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
||||
auto set = mDescriptorSetCache.createSet(dsh, layout);
|
||||
auto set = mDescriptorSetManager.createSet(dsh, layout);
|
||||
set.inc();
|
||||
}
|
||||
|
||||
@@ -1057,7 +1060,7 @@ bool VulkanDriver::isDepthStencilBlitSupported(TextureFormat format) {
|
||||
formats.end();
|
||||
}
|
||||
|
||||
bool VulkanDriver::isProtectedTexturesSupported() { return isProtectedContentSupported(); }
|
||||
bool VulkanDriver::isProtectedTexturesSupported() { return false; }
|
||||
|
||||
bool VulkanDriver::isDepthClampSupported() {
|
||||
return mContext.isDepthClampSupported();
|
||||
@@ -1134,28 +1137,24 @@ math::float2 VulkanDriver::getClipSpaceParams() {
|
||||
}
|
||||
|
||||
uint8_t VulkanDriver::getMaxDrawBuffers() {
|
||||
return mContext.getPhysicalDeviceLimits().maxColorAttachments;
|
||||
return MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; // TODO: query real value
|
||||
}
|
||||
|
||||
size_t VulkanDriver::getMaxUniformBufferSize() {
|
||||
return mContext.getPhysicalDeviceLimits().maxUniformBufferRange;
|
||||
// TODO: return the actual size instead of hardcoded value
|
||||
// TODO: devices that return less than 32768 should be rejected. This represents only 3%
|
||||
// of android devices.
|
||||
return 32768;
|
||||
}
|
||||
|
||||
size_t VulkanDriver::getMaxTextureSize(SamplerType type) {
|
||||
switch (type) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
return mContext.getPhysicalDeviceLimits().maxImageDimension2D;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return mContext.getPhysicalDeviceLimits().maxImageDimension3D;
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
return mContext.getPhysicalDeviceLimits().maxImageDimensionCube;
|
||||
default:
|
||||
return mContext.getPhysicalDeviceLimits().maxImageDimension1D;
|
||||
}
|
||||
size_t VulkanDriver::getMaxTextureSize(SamplerType) {
|
||||
// TODO: return the actual size instead of hardcoded value
|
||||
return 2048;
|
||||
}
|
||||
|
||||
size_t VulkanDriver::getMaxArrayTextureLayers() {
|
||||
return mContext.getPhysicalDeviceLimits().maxImageArrayLayers;
|
||||
// TODO: return the actual size instead of hardcoded value
|
||||
return 256;
|
||||
}
|
||||
|
||||
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||
@@ -1494,7 +1493,7 @@ void VulkanDriver::nextSubpass(int) {
|
||||
|
||||
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
||||
VulkanAttachment& subpassInput = renderTarget->getColor0();
|
||||
mDescriptorSetCache.updateInputAttachment({}, subpassInput);
|
||||
mDescriptorSetManager.updateInputAttachment({}, subpassInput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1821,9 +1820,9 @@ void VulkanDriver::bindDescriptorSet(
|
||||
backend::DescriptorSetOffsetArray&& offsets) {
|
||||
if (dsh) {
|
||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||
mDescriptorSetCache.bind(setIndex, set, std::move(offsets));
|
||||
mDescriptorSetManager.bind(setIndex, set, std::move(offsets));
|
||||
} else {
|
||||
mDescriptorSetCache.unbind(setIndex);
|
||||
mDescriptorSetManager.unbind(setIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1831,7 +1830,7 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
||||
|
||||
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
|
||||
mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer,
|
||||
mBoundPipeline.pipelineLayout,
|
||||
mBoundPipeline.descriptorSetMask);
|
||||
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
#include "VulkanSamplerCache.h"
|
||||
#include "VulkanStagePool.h"
|
||||
#include "VulkanQueryManager.h"
|
||||
#include "vulkan/VulkanDescriptorSetCache.h"
|
||||
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
|
||||
#include "vulkan/VulkanPipelineLayoutCache.h"
|
||||
#include "vulkan/caching/VulkanDescriptorSetManager.h"
|
||||
#include "vulkan/caching/VulkanPipelineLayoutCache.h"
|
||||
#include "vulkan/memory/ResourceManager.h"
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
#include "vulkan/utils/Definitions.h"
|
||||
@@ -138,8 +137,7 @@ private:
|
||||
VulkanSamplerCache mSamplerCache;
|
||||
VulkanBlitter mBlitter;
|
||||
VulkanReadPixels mReadPixels;
|
||||
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
||||
VulkanDescriptorSetCache mDescriptorSetCache;
|
||||
VulkanDescriptorSetManager mDescriptorSetManager;
|
||||
VulkanQueryManager mQueryManager;
|
||||
|
||||
// This is necessary for us to write to push constants after binding a pipeline.
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
|
||||
#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__)
|
||||
|
||||
@@ -55,61 +55,63 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
|
||||
VK_COMPONENT_SWIZZLE_A,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
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];
|
||||
}
|
||||
return { vals[0], vals[1], vals[2], vals[3] };
|
||||
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;
|
||||
};
|
||||
|
||||
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];
|
||||
auto const identityToChannel = [](VkComponentSwizzle val, uint8_t channelIndex) {
|
||||
if (val != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||
return val;
|
||||
}
|
||||
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] };
|
||||
return IDENTITY[channelIndex];
|
||||
};
|
||||
|
||||
// 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);
|
||||
VkComponentMapping const nextExplicit = identityToChannel(next);
|
||||
return channelToIdentity(compose(prevExplicit, nextExplicit));
|
||||
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),
|
||||
};
|
||||
}
|
||||
|
||||
inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
||||
@@ -151,6 +153,7 @@ uint8_t getLayerCountFromDepth(uint32_t const depth) {
|
||||
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
||||
}
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
||||
@@ -246,19 +249,12 @@ 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) &&
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
mState->mIsTransientAttachment = useTransientAttachment;
|
||||
|
||||
const VkImageUsageFlags transientFlag =
|
||||
|
||||
+120
-18
@@ -14,25 +14,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "VulkanDescriptorSetCache.h"
|
||||
#include "VulkanDescriptorSetManager.h"
|
||||
|
||||
#include "VulkanCommands.h"
|
||||
#include "VulkanHandles.h"
|
||||
#include "VulkanConstants.h"
|
||||
#include "vulkan/VulkanCommands.h"
|
||||
#include "vulkan/VulkanHandles.h"
|
||||
#include "vulkan/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 = VulkanDescriptorSetCache::DescriptorSetLayoutArray;
|
||||
using DescriptorSetLayoutArray = VulkanDescriptorSetManager::DescriptorSetLayoutArray;
|
||||
using BitmaskGroupHashFn = utils::hash::MurmurHashFn<BitmaskGroup>;
|
||||
struct BitmaskGroupEqual {
|
||||
bool operator()(BitmaskGroup const& k1, BitmaskGroup const& k2) const {
|
||||
return k1 == k2;
|
||||
}
|
||||
};
|
||||
|
||||
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
||||
// example, a layout of
|
||||
@@ -189,12 +199,72 @@ 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 VulkanDescriptorSetCache::DescriptorInfinitePool {
|
||||
class VulkanDescriptorSetManager::DescriptorInfinitePool {
|
||||
private:
|
||||
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
|
||||
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
|
||||
@@ -249,34 +319,61 @@ private:
|
||||
std::vector<std::unique_ptr<DescriptorPool>> mPools;
|
||||
};
|
||||
|
||||
class VulkanDescriptorSetManager::DescriptorSetLayoutManager {
|
||||
public:
|
||||
DescriptorSetLayoutManager(VkDevice device)
|
||||
: mDevice(device) {}
|
||||
|
||||
VulkanDescriptorSetCache::VulkanDescriptorSetCache(VkDevice 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,
|
||||
fvkmemory::ResourceManager* resourceManager)
|
||||
: mDevice(device),
|
||||
mResourceManager(resourceManager),
|
||||
mLayoutManager(std::make_unique<DescriptorSetLayoutManager>(device)),
|
||||
mDescriptorPool(std::make_unique<DescriptorInfinitePool>(device)) {}
|
||||
|
||||
VulkanDescriptorSetCache::~VulkanDescriptorSetCache() = default;
|
||||
VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default;
|
||||
|
||||
void VulkanDescriptorSetCache::terminate() noexcept{
|
||||
void VulkanDescriptorSetManager::terminate() noexcept{
|
||||
mLayoutManager.reset();
|
||||
mDescriptorPool.reset();
|
||||
clearHistory();
|
||||
}
|
||||
|
||||
// bind() is not really binding the set but just stashing until we have all the info
|
||||
// (pipelinelayout).
|
||||
void VulkanDescriptorSetCache::bind(uint8_t setIndex,
|
||||
void VulkanDescriptorSetManager::bind(uint8_t setIndex,
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
backend::DescriptorSetOffsetArray&& offsets) {
|
||||
set->setOffsets(std::move(offsets));
|
||||
mStashedSets[setIndex] = set;
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
|
||||
void VulkanDescriptorSetManager::unbind(uint8_t setIndex) {
|
||||
mStashedSets[setIndex] = {};
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
||||
void VulkanDescriptorSetManager::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.
|
||||
@@ -315,7 +412,7 @@ void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
||||
};
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
|
||||
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
||||
VkDescriptorBufferInfo const info = {
|
||||
@@ -341,7 +438,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
|
||||
set->acquire(bufferObject);
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
||||
VkSampler sampler) noexcept {
|
||||
VkDescriptorImageInfo info{
|
||||
@@ -373,13 +470,13 @@ void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescr
|
||||
set->acquire(texture);
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::updateInputAttachment(
|
||||
void VulkanDescriptorSetManager::updateInputAttachment(
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||
VulkanAttachment const& attachment) noexcept {
|
||||
// TOOD: fill this in.
|
||||
// TOOD: fill-in this region
|
||||
}
|
||||
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet(
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetManager::createSet(
|
||||
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||
auto const vkSet = mDescriptorPool->obtainSet(layout);
|
||||
auto const& count = layout->count;
|
||||
@@ -395,7 +492,12 @@ fvkmemory::resource_ptr<VulkanDescriptorSet> VulkanDescriptorSetCache::createSet
|
||||
});
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetCache::clearHistory() {
|
||||
void VulkanDescriptorSetManager::initVkLayout(
|
||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||
layout->setVkLayout(mLayoutManager->getVkLayout(layout->bitmask));
|
||||
}
|
||||
|
||||
void VulkanDescriptorSetManager::clearHistory() {
|
||||
mStashedSets = {};
|
||||
}
|
||||
|
||||
+16
-8
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||
|
||||
#include "VulkanHandles.h"
|
||||
#include "vulkan/VulkanHandles.h"
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
|
||||
|
||||
@@ -34,16 +34,20 @@
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
// Abstraction over the descriptor set pool.
|
||||
class VulkanDescriptorSetCache {
|
||||
// [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 {
|
||||
public:
|
||||
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
|
||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
|
||||
|
||||
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
||||
|
||||
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||
~VulkanDescriptorSetCache();
|
||||
VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||
~VulkanDescriptorSetManager();
|
||||
|
||||
void terminate() noexcept;
|
||||
|
||||
@@ -68,9 +72,12 @@ 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 =
|
||||
@@ -78,6 +85,7 @@ private:
|
||||
|
||||
VkDevice mDevice;
|
||||
fvkmemory::ResourceManager* mResourceManager;
|
||||
std::unique_ptr<DescriptorSetLayoutManager> mLayoutManager;
|
||||
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
|
||||
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
||||
DescriptorSetArray mStashedSets = {};
|
||||
@@ -91,4 +99,4 @@ private:
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
||||
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||
+1
-2
@@ -17,8 +17,7 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||
|
||||
#include "VulkanHandles.h"
|
||||
|
||||
#include <vulkan/VulkanHandles.h>
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -736,6 +736,10 @@ 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);
|
||||
@@ -755,10 +759,6 @@ 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,15 +1000,6 @@ 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,9 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||
#include <private/backend/BackendUtilsAndroid.h>
|
||||
|
||||
#include "vulkan/VulkanConstants.h"
|
||||
@@ -156,7 +157,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;
|
||||
@@ -199,12 +200,14 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
||||
return data;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
} // namespace
|
||||
|
||||
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||
namespace fvkandroid {
|
||||
|
||||
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
||||
AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
||||
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||
@@ -223,23 +226,12 @@ Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
||||
return Platform::ExternalImageHandle{};
|
||||
}
|
||||
|
||||
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
|
||||
ExternalImageHandleRef externalImage) const noexcept {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
} // namespace fvkandroid
|
||||
|
||||
return {
|
||||
.width = fvkExternalImage->width,
|
||||
.height = fvkExternalImage->height,
|
||||
.format = fvkExternalImage->format,
|
||||
.usage = fvkExternalImage->usage,
|
||||
};
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
|
||||
ExternalImageHandleRef externalImage) {
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
|
||||
ExternalImageMetadata metadata;
|
||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||
@@ -253,7 +245,7 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
||||
std::tie(metadata.format, metadata.usage) =
|
||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||
}
|
||||
|
||||
|
||||
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||
@@ -264,11 +256,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||
.pNext = &formatInfo,
|
||||
};
|
||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(getDevice(), buffer, &properties);
|
||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, 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("
|
||||
@@ -279,14 +271,14 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
||||
return metadata;
|
||||
}
|
||||
|
||||
VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
|
||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata,
|
||||
memoryTypeIndex, usage);
|
||||
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
|
||||
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||
return data;
|
||||
@@ -405,14 +397,14 @@ VkSampler VulkanPlatform::createExternalSamplerImpl(
|
||||
return sampler;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
return {
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
}
|
||||
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) const noexcept {
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) noexcept {
|
||||
VkSurfaceKHR surface;
|
||||
VkExtent2D extent;
|
||||
|
||||
@@ -424,26 +416,6 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
|
||||
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::getSwapchainInstanceExtensionsImpl() {
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
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::createVkSurfaceKHRImpl(void* nativeWindow,
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(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::getSwapchainInstanceExtensionsImpl() {
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
VulkanPlatform::ExtensionSet const ret = {
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
||||
@@ -126,7 +126,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
|
||||
return ret;
|
||||
}
|
||||
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) noexcept {
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
|
||||
@@ -651,11 +651,11 @@ uint8_t WebGPUDriver::getMaxDrawBuffers() {
|
||||
return MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxUniformBufferSize() {
|
||||
size_t WebGPUDriver::getMaxUniformBufferSize(SamplerType) {
|
||||
return 16384u;
|
||||
}
|
||||
|
||||
size_t WebGPUDriver::getMaxTextureSize(SamplerType target) {
|
||||
size_t WebGPUDriver::getMaxTextureSize() {
|
||||
return 2048u;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||
return device;
|
||||
}
|
||||
|
||||
Driver* WebGPUPlatform::createDriver(void* sharedContext,
|
||||
Driver* WebGPUPlatform::createDriver(void* const sharedContext,
|
||||
const Platform::DriverConfig& /*driverConfig*/) noexcept {
|
||||
if (sharedContext) {
|
||||
FWGPU_LOGW << "sharedContext is ignored/unused in the WebGPU backend. A non-null "
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
@@ -120,9 +118,7 @@ wgpu::Surface WebGPUPlatform::createSurface(void* nativeWindow, uint64_t flags)
|
||||
if (useXcb) {
|
||||
wgpu::SurfaceSourceXCBWindow surfaceSourceXcb{};
|
||||
surfaceSourceXcb.connection = g_x11.connection;
|
||||
|
||||
// TODO: this looks really wrong, please fix!!
|
||||
surfaceSourceXcb.window = *((uint32_t*) nativeWindow);
|
||||
surfaceSourceXcb.window = reinterpret_cast<uint32_t>(nativeWindow);
|
||||
wgpu::SurfaceDescriptor surfaceDescriptor{
|
||||
.nextInChain = &surfaceSourceXcb,
|
||||
.label = "linux_xcb_surface"
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ImageExpectations.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "utils/Hash.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "backend/PixelBufferDescriptor.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#ifndef FILAMENT_IOS
|
||||
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
#endif
|
||||
|
||||
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
||||
uint32_t expectedPixelHash)
|
||||
: mWidth(width), mHeight(height), mFileName(std::move(fileName)),
|
||||
mExpectedPixelHash(expectedPixelHash) {}
|
||||
|
||||
int ScreenshotParams::width() const {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
int ScreenshotParams::height() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
uint32_t ScreenshotParams::expectedHash() const {
|
||||
return mExpectedPixelHash;
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::outputDirectoryPath() const {
|
||||
return ".";
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::generatedActualFileName() const {
|
||||
return absl::StrFormat("%s_actual.png", mFileName);
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::generatedActualFilePath() const {
|
||||
return absl::StrFormat("%s/%s", outputDirectoryPath(), generatedActualFileName());
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::goldenFileName() const {
|
||||
return absl::StrFormat("%s_golden.png", mFileName);
|
||||
}
|
||||
|
||||
std::string ScreenshotParams::goldenFilePath() const {
|
||||
return absl::StrFormat("%s/%s", outputDirectoryPath(), goldenFileName());
|
||||
}
|
||||
|
||||
ImageExpectation::ImageExpectation(const char* fileName, int lineNumber,
|
||||
filament::backend::DriverApi& api, ScreenshotParams params,
|
||||
filament::backend::RenderTargetHandle renderTarget)
|
||||
: mFileName(fileName), mLineNumber(lineNumber), mParams(std::move(params)),
|
||||
mResult(api, renderTarget, mParams) {}
|
||||
|
||||
void ImageExpectation::evaluate() {
|
||||
// Ensure this is only evaluated once.
|
||||
if (mEvaluated) {
|
||||
return;
|
||||
}
|
||||
mEvaluated = true;
|
||||
|
||||
// Do the actual image comparison inside a scoped trace with the stored file and line.
|
||||
{
|
||||
testing::ScopedTrace trace(mFileName, mLineNumber, "");
|
||||
compareImage();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageExpectation::compareImage() const {
|
||||
bool bytesFilled = mResult.bytesFilled();
|
||||
EXPECT_THAT(bytesFilled, testing::IsTrue())
|
||||
<< "Render target wasn't copied to the buffer for " << mFileName;
|
||||
if (bytesFilled) {
|
||||
uint32_t actualHash = mResult.hash();
|
||||
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash()));
|
||||
}
|
||||
}
|
||||
|
||||
ImageExpectations::ImageExpectations(filament::backend::DriverApi& api) : mApi(api) {}
|
||||
|
||||
ImageExpectations::~ImageExpectations() {
|
||||
// Guarantee that all expectations are evaluated when this leaves scope even if the caller
|
||||
// forgot to manually evaluate them.
|
||||
evaluate();
|
||||
}
|
||||
|
||||
void ImageExpectations::addExpectation(const char* fileName, int lineNumber,
|
||||
filament::backend::RenderTargetHandle renderTarget, ScreenshotParams params) {
|
||||
mExpectations.emplace_back(fileName, lineNumber, mApi, std::move(params), renderTarget);
|
||||
}
|
||||
|
||||
void ImageExpectations::evaluate() {
|
||||
for (auto& expectation: mExpectations) {
|
||||
expectation.evaluate();
|
||||
}
|
||||
mExpectations.clear();
|
||||
}
|
||||
|
||||
RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
|
||||
filament::backend::RenderTargetHandle renderTarget, const ScreenshotParams& params)
|
||||
: mInternal(std::make_unique<RenderTargetDump::Internal>(params)) {
|
||||
#ifdef FILAMENT_IOS
|
||||
bytesFilled_ = true;
|
||||
bytes_.resize(size);
|
||||
std::fill(bytes_.begin(), bytes_.end(), 0);
|
||||
#else
|
||||
const size_t size = mInternal->params.width() * mInternal->params.height() * 4;
|
||||
mInternal->bytes.resize(size);
|
||||
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
|
||||
image::LinearImage image(internal->params.width(), internal->params.width(), 4);
|
||||
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
|
||||
internal->params.height(),
|
||||
internal->params.width() * 4, (uint8_t*)buffer);
|
||||
std::string filePath = internal->params.generatedActualFilePath();
|
||||
std::ofstream pngStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG, image, "",
|
||||
filePath);
|
||||
internal->bytesFilled = true;
|
||||
};
|
||||
filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size,
|
||||
filament::backend::PixelDataFormat::RGBA, filament::backend::PixelDataType::UBYTE, cb,
|
||||
(void*)mInternal.get());
|
||||
api.readPixels(renderTarget, 0, 0, mInternal->params.width(), mInternal->params.height(),
|
||||
std::move(pb));
|
||||
#endif
|
||||
}
|
||||
|
||||
RenderTargetDump::~RenderTargetDump() {
|
||||
// If the GPU callback hasn't been made yet then there's a callback elsewhere that has a copy of
|
||||
// the internal pointer. But there's no guarantee that the callback will be ever made if the GPU
|
||||
// pipeline wasn't run for some reason. So it is necessary to leak the memory.
|
||||
// It would be possible to try to coordinate with the callback to have it clean up the memory,
|
||||
// but if this condition happens there's already an issue with the test case so there's no need.
|
||||
if (!bytesFilled()) {
|
||||
mInternal.release();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RenderTargetDump::hash() const {
|
||||
return utils::hash::murmur3((uint32_t*)mInternal->bytes.data(), mInternal->bytes.size() / 4, 0);
|
||||
}
|
||||
|
||||
bool RenderTargetDump::bytesFilled() const {
|
||||
return mInternal->bytesFilled;
|
||||
}
|
||||
|
||||
RenderTargetDump::Internal::Internal(const ScreenshotParams& params) : params(params) {}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_IMAGE_EXPECTATIONS_H
|
||||
#define TNT_IMAGE_EXPECTATIONS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "backend/Handle.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
|
||||
// Arguments are (RenderTargetHandle renderTarget, ImageExpectations& expectations,
|
||||
// ScreenshotParams screenshotParams)
|
||||
#define EXPECT_IMAGE(renderTarget, expectations, screenshotParams) \
|
||||
do { \
|
||||
expectations.addExpectation( \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
renderTarget, \
|
||||
screenshotParams); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Stores user-provided configuration values for an image expectation
|
||||
*/
|
||||
class ScreenshotParams {
|
||||
public:
|
||||
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash);
|
||||
|
||||
int width() const;
|
||||
int height() const;
|
||||
uint32_t expectedHash() const;
|
||||
|
||||
std::string outputDirectoryPath() const;
|
||||
std::string generatedActualFileName() const;
|
||||
std::string generatedActualFilePath() const;
|
||||
std::string goldenFileName() const;
|
||||
std::string goldenFilePath() const;
|
||||
|
||||
private:
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
uint32_t mExpectedPixelHash;
|
||||
std::string mFileName;
|
||||
};
|
||||
|
||||
/**
|
||||
* When created adds a command to the GPU pipeline to copy the render target into a buffer and
|
||||
* stores the result.
|
||||
* If this object is destroyed before the GPU pipeline is flushed it will leak memory in order to
|
||||
* avoid the GPU pipeline callback being a use-after-free.
|
||||
*/
|
||||
class RenderTargetDump {
|
||||
public:
|
||||
RenderTargetDump(filament::backend::DriverApi& api,
|
||||
filament::backend::RenderTargetHandle renderTarget, const ScreenshotParams& params);
|
||||
RenderTargetDump(RenderTargetDump&& other) = default;
|
||||
RenderTargetDump& operator=(RenderTargetDump&& other) = default;
|
||||
~RenderTargetDump();
|
||||
|
||||
/**
|
||||
* Should only bue used if BytesFilled returns true.
|
||||
* @return The hash of the stored bytes.
|
||||
*/
|
||||
uint32_t hash() const;
|
||||
/**
|
||||
* Thread safe as this is backed by an atomic.
|
||||
* Once this returns true it will never return false.
|
||||
* @return Whether the bytes have actually been copied from the GPU to the buffer.
|
||||
*/
|
||||
bool bytesFilled() const;
|
||||
|
||||
private:
|
||||
struct Internal {
|
||||
explicit Internal(const ScreenshotParams& params);
|
||||
ScreenshotParams params;
|
||||
std::atomic<bool> bytesFilled = false;
|
||||
std::vector<unsigned char> bytes;
|
||||
};
|
||||
|
||||
// We need a memory location that won't be invalidated to pass to GPU callbacks as they can't
|
||||
// be canceled during the destructor.
|
||||
std::unique_ptr<Internal> mInternal;
|
||||
};
|
||||
|
||||
class ImageExpectation {
|
||||
public:
|
||||
ImageExpectation(const char* fileName, int lineNumber, filament::backend::DriverApi& api,
|
||||
ScreenshotParams params, filament::backend::RenderTargetHandle renderTarget);
|
||||
|
||||
void evaluate();
|
||||
|
||||
private:
|
||||
void compareImage() const;
|
||||
|
||||
bool mEvaluated = false;
|
||||
const char* mFileName;
|
||||
int mLineNumber;
|
||||
ScreenshotParams mParams;
|
||||
RenderTargetDump mResult;
|
||||
};
|
||||
|
||||
class ImageExpectations {
|
||||
public:
|
||||
explicit ImageExpectations(filament::backend::DriverApi& api);
|
||||
~ImageExpectations();
|
||||
|
||||
/**
|
||||
* Not meant to be called directly, use EXPECT_IMAGE to get the file name and line number
|
||||
*/
|
||||
void addExpectation(const char* fileName, int lineNumber,
|
||||
filament::backend::RenderTargetHandle renderTarget, ScreenshotParams params);
|
||||
|
||||
void evaluate();
|
||||
|
||||
private:
|
||||
filament::backend::DriverApi& mApi;
|
||||
std::vector<ImageExpectation> mExpectations;
|
||||
};
|
||||
|
||||
#endif //TNT_IMAGE_EXPECTATIONS_H
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Shader.h"
|
||||
|
||||
#include "BackendTest.h"
|
||||
#include "ShaderGenerator.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
using namespace filament::backend;
|
||||
|
||||
Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) {
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> kLayouts(config.uniformNames.size());
|
||||
for (unsigned char i = 0; i < config.uniformNames.size(); ++i) {
|
||||
kLayouts[i] =
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, i };
|
||||
};
|
||||
|
||||
filamat::DescriptorSets descriptors;
|
||||
for (unsigned char i = 0; i < config.uniformNames.size(); ++i) {
|
||||
descriptors[i + 1] = {{ config.uniformNames[i], kLayouts[i], {}}};
|
||||
}
|
||||
ShaderGenerator shaderGen(
|
||||
std::move(config.vertexShader), std::move(config.fragmentShader), BackendTest::sBackend,
|
||||
BackendTest::sIsMobilePlatform, std::move(descriptors));
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
for (unsigned char i = 0; i < config.uniformNames.size(); ++i) {
|
||||
prog.descriptorBindings(1, {{ config.uniformNames[i], DescriptorType::UNIFORM_BUFFER, i }});
|
||||
}
|
||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||
|
||||
mDescriptorSetLayout = cleanup.add(
|
||||
api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
||||
|
||||
mDescriptorSet = cleanup.add(api.createDescriptorSet(mDescriptorSetLayout));
|
||||
}
|
||||
|
||||
filament::backend::ProgramHandle Shader::getProgram() const {
|
||||
return mProgram;
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||
return mDescriptorSetLayout;
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetHandle Shader::getDescriptorSet() const {
|
||||
return mDescriptorSet;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_SHADER_H
|
||||
#define TNT_SHADER_H
|
||||
|
||||
#include "Lifetimes.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
// All describing a shader that should be created.
|
||||
struct ShaderConfig {
|
||||
std::string vertexShader;
|
||||
std::string fragmentShader;
|
||||
std::vector<utils::CString> uniformNames;
|
||||
};
|
||||
|
||||
// All values describing a uniform.
|
||||
struct ResolvedUniformBindingConfig {
|
||||
size_t dataSize;
|
||||
size_t bufferSize;
|
||||
uint32_t byteOffset;
|
||||
filament::backend::descriptor_set_t set;
|
||||
filament::backend::descriptor_binding_t binding;
|
||||
};
|
||||
|
||||
// An equivalent to ResolvedUniformBindingConfig with all fields optional.
|
||||
// resolve can be called to create a ResolvedBindingConfig with default values
|
||||
// use in place of nullopt values.
|
||||
struct UniformBindingConfig {
|
||||
std::optional<size_t> dataSize;
|
||||
std::optional<size_t> bufferSize;
|
||||
std::optional<uint32_t> byteOffset;
|
||||
std::optional<filament::backend::descriptor_set_t> set;
|
||||
std::optional<filament::backend::descriptor_binding_t> binding;
|
||||
|
||||
template<typename UniformType>
|
||||
ResolvedUniformBindingConfig resolve();
|
||||
};
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
// All graphics resources have their lifetime controlled by the Cleanup and not this object.
|
||||
// Shader must not outlive either the DriverApi or the Cleanup.
|
||||
Shader(filament::backend::DriverApi& api, Cleanup& cleanup, ShaderConfig config);
|
||||
|
||||
// Uploads a uniform with the default config.
|
||||
template<typename UniformType>
|
||||
void uploadUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformType uniforms) const;
|
||||
// Binds a uniform with the default config.
|
||||
template<typename UniformType>
|
||||
void bindUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer) const;
|
||||
// Uploads a uniform, with UniformBindingConfig providing the arguments.
|
||||
template<typename UniformType>
|
||||
void uploadUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformBindingConfig config, UniformType uniforms) const;
|
||||
// Binds a uniform, with UniformBindingConfig providing the arguments.
|
||||
template<typename UniformType>
|
||||
void bindUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformBindingConfig config) const;
|
||||
|
||||
filament::backend::ProgramHandle getProgram() const;
|
||||
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
|
||||
filament::backend::DescriptorSetHandle getDescriptorSet() const;
|
||||
|
||||
protected:
|
||||
filament::backend::ProgramHandle mProgram;
|
||||
filament::backend::DescriptorSetLayoutHandle mDescriptorSetLayout;
|
||||
filament::backend::DescriptorSetHandle mDescriptorSet;
|
||||
};
|
||||
|
||||
template<typename UniformType>
|
||||
ResolvedUniformBindingConfig UniformBindingConfig::resolve() {
|
||||
auto resolvedDataSize = dataSize.value_or(sizeof(UniformType));
|
||||
return ResolvedUniformBindingConfig{
|
||||
.dataSize = resolvedDataSize,
|
||||
.bufferSize = bufferSize.value_or(resolvedDataSize),
|
||||
.byteOffset = byteOffset.value_or(0),
|
||||
.set = set.value_or(1),
|
||||
.binding = binding.value_or(0)
|
||||
};
|
||||
}
|
||||
|
||||
template<typename UniformType>
|
||||
void Shader::uploadUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformBindingConfig config, UniformType uniforms) const {
|
||||
auto resolvedConfig = config.resolve<UniformType>();
|
||||
|
||||
UniformType* tmp = new UniformType(uniforms);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
UniformType* sp = (UniformType*)buffer;
|
||||
delete sp;
|
||||
};
|
||||
filament::backend::BufferDescriptor bd(tmp, resolvedConfig.dataSize, cb);
|
||||
api.updateBufferObject(hwBuffer, std::move(bd), resolvedConfig.byteOffset);
|
||||
}
|
||||
|
||||
template<typename UniformType>
|
||||
void Shader::bindUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformBindingConfig config) const {
|
||||
auto resolvedConfig = config.resolve<UniformType>();
|
||||
|
||||
api.updateDescriptorSetBuffer(getDescriptorSet(), resolvedConfig.binding, hwBuffer, 0,
|
||||
resolvedConfig.bufferSize);
|
||||
api.bindDescriptorSet(getDescriptorSet(), resolvedConfig.set, {});
|
||||
}
|
||||
|
||||
template<typename UniformType>
|
||||
void Shader::uploadUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
|
||||
UniformType uniforms) const {
|
||||
uploadUniform(api, hwBuffer, UniformBindingConfig{}, uniforms);
|
||||
}
|
||||
|
||||
template<typename UniformType>
|
||||
void Shader::bindUniform(filament::backend::DriverApi& api,
|
||||
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer) const {
|
||||
bindUniform<UniformType>(api, hwBuffer, UniformBindingConfig{});
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif //TNT_SHADER_H
|
||||
+260
-208
@@ -16,9 +16,8 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "ImageExpectations.h"
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -27,10 +26,8 @@
|
||||
#include <fstream>
|
||||
|
||||
#ifndef FILAMENT_IOS
|
||||
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace test {
|
||||
@@ -40,21 +37,6 @@ using namespace filament::backend;
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
|
||||
struct MaterialParams {
|
||||
float4 color;
|
||||
float4 scale;
|
||||
};
|
||||
|
||||
class BlitTest : public BackendTest {
|
||||
public:
|
||||
BlitTest() : mCleanup(getDriverApi()) {}
|
||||
|
||||
protected:
|
||||
Shader createShader();
|
||||
|
||||
Cleanup mCleanup;
|
||||
};
|
||||
|
||||
static const char* const triangleVs = R"(#version 450 core
|
||||
layout(location = 0) in vec4 mesh_position;
|
||||
layout(binding = 0, set = 1) uniform Params { highp vec4 color; highp vec4 scale; } params;
|
||||
@@ -74,12 +56,49 @@ void main() {
|
||||
fragColor = params.color;
|
||||
})";
|
||||
|
||||
Shader BlitTest::createShader() {
|
||||
return Shader(getDriverApi(), mCleanup, ShaderConfig{
|
||||
.vertexShader = triangleVs,
|
||||
.fragmentShader = triangleFs,
|
||||
.uniformNames = { "Params" },
|
||||
});
|
||||
struct MaterialParams {
|
||||
float4 color;
|
||||
float4 scale;
|
||||
};
|
||||
|
||||
struct ScreenshotParams {
|
||||
int width;
|
||||
int height;
|
||||
const char* filename;
|
||||
uint32_t pixelHashResult;
|
||||
};
|
||||
|
||||
#ifdef FILAMENT_IOS
|
||||
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, ScreenshotParams* params) {}
|
||||
#else
|
||||
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, ScreenshotParams* params) {
|
||||
using namespace image;
|
||||
const size_t size = params->width * params->height * 4;
|
||||
void* buffer = calloc(1, size);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
ScreenshotParams* params = (ScreenshotParams*) user;
|
||||
int w = params->width, h = params->height;
|
||||
const uint32_t* texels = (uint32_t*) buffer;
|
||||
params->pixelHashResult = utils::hash::murmur3(texels, size / 4, 0);
|
||||
LinearImage image(w, h, 4);
|
||||
image = toLinearWithAlpha<uint8_t>(w, h, w * 4, (uint8_t*) buffer);
|
||||
std::ofstream pngstrm(params->filename, std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(pngstrm, ImageEncoder::Format::PNG, image, "", params->filename);
|
||||
};
|
||||
PixelBufferDescriptor pb(buffer, size, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb,
|
||||
(void*) params);
|
||||
dapi.readPixels(rt, 0, 0, params->width, params->height, std::move(pb));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uploadUniforms(DriverApi& dapi, Handle<HwBufferObject> ubh, MaterialParams params) {
|
||||
MaterialParams* tmp = new MaterialParams(params);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
MaterialParams* sp = (MaterialParams*) buffer;
|
||||
delete sp;
|
||||
};
|
||||
BufferDescriptor bd(tmp, sizeof(MaterialParams), cb);
|
||||
dapi.updateBufferObject(ubh, std::move(bd), 0);
|
||||
}
|
||||
|
||||
static uint32_t toUintColor(float4 color) {
|
||||
@@ -97,7 +116,7 @@ static void createBitmap(DriverApi& dapi, Handle<HwTexture> texture, int baseWid
|
||||
const int width = baseWidth >> level;
|
||||
const int height = baseHeight >> level;
|
||||
const size_t size0 = height * width * 4;
|
||||
uint8_t* buffer0 = (uint8_t*)calloc(size0, 1);
|
||||
uint8_t* buffer0 = (uint8_t*) calloc(size0, 1);
|
||||
PixelBufferDescriptor pb(buffer0, size0, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb);
|
||||
|
||||
const float3 foreground = color;
|
||||
@@ -121,7 +140,7 @@ static void createBitmap(DriverApi& dapi, Handle<HwTexture> texture, int baseWid
|
||||
// | ........
|
||||
// low addresses
|
||||
// This is because OpenGL automatically flips image data when uploading into the texture.
|
||||
uint32_t* texels = (uint32_t*)buffer0;
|
||||
uint32_t* texels = (uint32_t*) buffer0;
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
float2 uv = { (col - width / 2.0f) / width, (row - height / 2.0f) / height };
|
||||
@@ -149,7 +168,7 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
const int width = baseWidth >> level;
|
||||
const int height = baseHeight >> level;
|
||||
const size_t size0 = height * width * 4 * 6;
|
||||
uint8_t* buffer0 = (uint8_t*)calloc(size0, 1);
|
||||
uint8_t* buffer0 = (uint8_t*) calloc(size0, 1);
|
||||
PixelBufferDescriptor pb(buffer0, size0, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb);
|
||||
|
||||
const float3 foreground = color;
|
||||
@@ -157,7 +176,7 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
const float radius = 0.25f;
|
||||
|
||||
// Draw a circle on a yellow background.
|
||||
uint32_t* texels = (uint32_t*)buffer0;
|
||||
uint32_t* texels = (uint32_t*) buffer0;
|
||||
for (int face = 0; face < 6; face++) {
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
@@ -175,9 +194,10 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
dapi.update3DImage(texture, level, 0, 0, 0, width, height, 6, std::move(pb));
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorMagnify) {
|
||||
TEST_F(BackendTest, ColorMagnify) {
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -188,40 +208,37 @@ TEST_F(BlitTest, ColorMagnify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {},
|
||||
{}));
|
||||
dstRenderTargets[level] = mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {},
|
||||
{}));
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Do a "magnify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
const int srcLevel = 1;
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTargets[0],
|
||||
{ 0, 0, kDstTexWidth, kDstTexHeight }, srcRenderTargets[srcLevel],
|
||||
{ 0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel },
|
||||
SamplerMagFilter::LINEAR);
|
||||
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTargets[srcLevel],
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
{
|
||||
@@ -229,23 +246,29 @@ TEST_F(BlitTest, ColorMagnify) {
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMagnify.png" };
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
EXPECT_IMAGE(dstRenderTargets[0], expectations,
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31));
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
flushAndWait();
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
const uint32_t expected = 0x410bdd31;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorMinify) {
|
||||
TEST_F(BackendTest, ColorMinify) {
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -256,55 +279,57 @@ TEST_F(BlitTest, ColorMinify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {},
|
||||
{}));
|
||||
dstRenderTargets[level] = mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {},
|
||||
{}));
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
const int srcLevel = 1;
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0,
|
||||
dstRenderTargets[0], { 0, 0, kDstTexWidth, kDstTexHeight },
|
||||
srcRenderTargets[srcLevel],
|
||||
{ 0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel },
|
||||
dstRenderTargets[0], {0, 0, kDstTexWidth, kDstTexHeight},
|
||||
srcRenderTargets[srcLevel], {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel},
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
|
||||
EXPECT_IMAGE(dstRenderTargets[0], expectations,
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f));
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMinify.png" };
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
|
||||
flushAndWait();
|
||||
}
|
||||
// Wait for the ReadPixels result to come back.
|
||||
flushAndWait();
|
||||
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
const uint32_t expected = 0xf3d9c53f;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorResolve) {
|
||||
TEST_F(BackendTest, ColorResolve) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -313,29 +338,49 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
constexpr auto kColorTexFormat = TextureFormat::RGBA8;
|
||||
constexpr int kSampleCount = 4;
|
||||
|
||||
Shader shader = createShader();
|
||||
// Create a program.
|
||||
ProgramHandle program;
|
||||
{
|
||||
filamat::DescriptorSets descriptors;
|
||||
descriptors[1] = { { "Params",
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0 },
|
||||
{} } };
|
||||
ShaderGenerator shaderGen(
|
||||
triangleVs, triangleFs, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
prog.descriptorBindings(1, {{ "Params", DescriptorType::UNIFORM_BUFFER, 0 }});
|
||||
program = cleanup.add(api.createProgram(std::move(prog)));
|
||||
}
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
|
||||
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
|
||||
TrianglePrimitive const triangle(api);
|
||||
|
||||
// Create 4-sample texture.
|
||||
Handle<HwTexture> const srcColorTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight,
|
||||
1,
|
||||
TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const srcColorTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create 1-sample texture.
|
||||
Handle<HwTexture> const dstColorTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> const dstColorTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a 4-sample render target with the 4-sample texture.
|
||||
Handle<HwRenderTarget> const srcRenderTarget = mCleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const srcRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount, 0,
|
||||
{{ srcColorTexture }}, {}, {}));
|
||||
|
||||
// Create a 1-sample render target with the 1-sample texture.
|
||||
Handle<HwRenderTarget> const dstRenderTarget = mCleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const dstRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, 0,
|
||||
{{ dstColorTexture }}, {}, {}));
|
||||
|
||||
@@ -349,52 +394,58 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
params.viewport.height = kSrcTexHeight;
|
||||
|
||||
PipelineState state = {};
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
||||
state.program = program;
|
||||
state.pipelineLayout.setLayout[1] = { descriptorSetLayout };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
auto ubuffer = mCleanup.add(api.createBufferObject(sizeof(MaterialParams),
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
// Draw red triangle into srcRenderTarget.
|
||||
shader.uploadUniform(api, ubuffer, MaterialParams{
|
||||
.color = float4(1, 0, 0, 1),
|
||||
.scale = float4(1, 1, 0.5, 0),
|
||||
uploadUniforms(api, ubuffer, {
|
||||
.color = float4(1, 0, 0, 1),
|
||||
.scale = float4(1, 1, 0.5, 0),
|
||||
});
|
||||
shader.bindUniform<MaterialParams>(api, ubuffer);
|
||||
|
||||
api.updateDescriptorSetBuffer(descriptorSet, 0, ubuffer, 0, sizeof(MaterialParams));
|
||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
||||
|
||||
// FIXME: on Metal this triangle is not drawn. Can't understand why.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.beginRenderPass(srcRenderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
}
|
||||
|
||||
// Resolve the MSAA render target into the single-sample render target.
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR,
|
||||
dstRenderTarget, { 0, 0, kDstTexWidth, kDstTexHeight },
|
||||
srcRenderTarget, { 0, 0, kSrcTexWidth, kSrcTexHeight },
|
||||
dstRenderTarget, {0, 0, kDstTexWidth, kDstTexHeight},
|
||||
srcRenderTarget, {0, 0, kSrcTexWidth, kSrcTexHeight},
|
||||
SamplerMagFilter::NEAREST);
|
||||
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams sparams{ kDstTexWidth, kDstTexHeight, "ColorResolve.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, &sparams);
|
||||
|
||||
EXPECT_IMAGE(dstRenderTarget, expectations,
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 0xebfac2ef));
|
||||
// Wait for the ReadPixels result to come back.
|
||||
flushAndWait();
|
||||
|
||||
flushAndWait();
|
||||
}
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
const uint32_t expected = 0xebfac2ef;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected);
|
||||
EXPECT_TRUE(sparams.pixelHashResult == expected);
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
api.startCapture(0);
|
||||
mCleanup.addPostCall([&]() { api.stopCapture(0); });
|
||||
cleanup.addPostCall([&]() { api.stopCapture(0); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -409,40 +460,33 @@ TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
constexpr int kDstTexLayer = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D_ARRAY, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth,
|
||||
kSrcTexHeight, kSrcTexDepth,
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D_ARRAY, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, kSrcTexDepth,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, kSrcTexLayer, float3(0.5, 0, 0),
|
||||
flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, kSrcTexLayer, float3(0.5, 0, 0), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = mCleanup.add(api.createTexture(
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create two RenderTargets.
|
||||
const int level = 0;
|
||||
Handle<HwRenderTarget> srcRenderTarget = mCleanup.add(
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0,
|
||||
{ srcTexture, level, kSrcTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget = mCleanup.add(
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0,
|
||||
{ dstTexture, level, kDstTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> srcRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {}));
|
||||
|
||||
// Do a blit from kSrcTexLayer of the source RT to kDstTexLayer of the destination RT.
|
||||
const int srcLevel = 0;
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
{ 0, 0, kDstTexWidth, kDstTexHeight }, srcRenderTarget,
|
||||
{ 0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel },
|
||||
SamplerMagFilter::LINEAR);
|
||||
{0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget,
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
{
|
||||
@@ -450,24 +494,29 @@ TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "Blit2DTextureArray.png" };
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
EXPECT_IMAGE(dstRenderTarget, expectations,
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "Blit2DTextureArray",
|
||||
0x8de7d55b));
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
flushAndWait();
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
const uint32_t expected = 0x8de7d55b;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, BlitRegion) {
|
||||
TEST_F(BackendTest, BlitRegion) {
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -480,48 +529,47 @@ TEST_F(BlitTest, BlitRegion) {
|
||||
constexpr int kDstLevel = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
Viewport srcRect = {
|
||||
.left = 0,
|
||||
.bottom = 0,
|
||||
.width = (kSrcTexWidth >> kSrcLevel) / 2,
|
||||
.height = (kSrcTexHeight >> kSrcLevel) / 2,
|
||||
.left = 0,
|
||||
.bottom = 0,
|
||||
.width = (kSrcTexWidth >> kSrcLevel) / 2,
|
||||
.height = (kSrcTexHeight >> kSrcLevel) / 2,
|
||||
};
|
||||
Viewport dstRect = {
|
||||
.left = 10,
|
||||
.bottom = 10,
|
||||
.width = kDstTexWidth - 10,
|
||||
.height = kDstTexHeight - 10,
|
||||
.left = 10,
|
||||
.bottom = 10,
|
||||
.width = kDstTexWidth - 10,
|
||||
.height = kDstTexHeight - 10,
|
||||
};
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
// We purposely set the render target width and height to smaller than the texture, to check
|
||||
// that this case is handled correctly.
|
||||
Handle<HwRenderTarget> srcRenderTarget =
|
||||
mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, { srcTexture, kSrcLevel, 0 }, {}, {}));
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget =
|
||||
mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, { dstTexture, kDstLevel, 0 }, {}, {}));
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {}));
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget,
|
||||
srcRect,
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
@@ -530,25 +578,33 @@ TEST_F(BlitTest, BlitRegion) {
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegion.png" };
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
// TODO: for some reason, this test has very, very slight (as in one pixel) differences
|
||||
// between OpenGL and Metal. So disable golden checking for now.
|
||||
// EXPECT_IMAGE(dstRenderTarget, expectations, ScreenshotParams(kDstTexWidth,
|
||||
// kDstTexHeight, "BlitRegion", 0x74fa34ed));
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
flushAndWait();
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// TODO: for some reason, this test has very, very slight (as in one pixel) differences between
|
||||
// OpenGL and Metal. So disable golden checking for now.
|
||||
// Use the compare tool from ImageMagick to see visual differences:
|
||||
// compare -verbose -metric mae BlitRegion_Metal.png BlitRegion_OpenGL.png difference.png
|
||||
//
|
||||
// const uint32_t expected = 0x74fa34ed;
|
||||
// printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
// EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||
TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -558,15 +614,15 @@ TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = mCleanup.add(createSwapChain());
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Handle<HwRenderTarget> dstRenderTarget = mCleanup.add(api.createDefaultRenderTarget());
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = mCleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
@@ -574,46 +630,42 @@ TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = mCleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {},
|
||||
{}));
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
const int srcLevel = 1;
|
||||
Viewport srcRect = {
|
||||
.left = (kSrcTexWidth >> srcLevel) / 2,
|
||||
.bottom = (kSrcTexHeight >> srcLevel) / 2,
|
||||
.width = (kSrcTexWidth >> srcLevel) / 2,
|
||||
.height = (kSrcTexHeight >> srcLevel) / 2,
|
||||
.left = (kSrcTexWidth >> srcLevel) / 2,
|
||||
.bottom = (kSrcTexHeight >> srcLevel) / 2,
|
||||
.width = (kSrcTexWidth >> srcLevel) / 2,
|
||||
.height = (kSrcTexHeight >> srcLevel) / 2,
|
||||
};
|
||||
Viewport dstRect = {
|
||||
.left = 10,
|
||||
.bottom = 10,
|
||||
.width = kDstTexWidth - 10,
|
||||
.height = kDstTexHeight - 10,
|
||||
.left = 10,
|
||||
.bottom = 10,
|
||||
.width = kDstTexWidth - 10,
|
||||
.height = kDstTexHeight - 10,
|
||||
};
|
||||
|
||||
{
|
||||
ImageExpectations expectations(api);
|
||||
{
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
RenderFrame frame(api);
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
|
||||
api.commit(swapChain);
|
||||
}
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
|
||||
// TODO: for some reason, this test has been disabled. It needs to be tested on all
|
||||
// machines.
|
||||
// EXPECT_IMAGE(dstRenderTarget, expectations,
|
||||
// ScreenshotParams(kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain", 0x0));
|
||||
}
|
||||
flushAndWait();
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -80,28 +78,8 @@ struct MaterialParams {
|
||||
math::float4 offset;
|
||||
};
|
||||
static_assert(sizeof(MaterialParams) == 8 * sizeof(float));
|
||||
// Uniform config for writing MaterialParams to the shader uniform with 64 bytes of padding.
|
||||
const UniformBindingConfig kBindingConfig = {
|
||||
.dataSize = sizeof(MaterialParams),
|
||||
.bufferSize = sizeof(MaterialParams) + 64,
|
||||
.byteOffset = 64
|
||||
};
|
||||
|
||||
class BufferUpdatesTest : public BackendTest {
|
||||
public:
|
||||
BufferUpdatesTest() : mCleanup(getDriverApi()) {}
|
||||
|
||||
protected:
|
||||
Shader createShader() {
|
||||
return Shader(getDriverApi(), mCleanup, ShaderConfig{
|
||||
vertex, fragment, {"Params"}
|
||||
});
|
||||
}
|
||||
|
||||
Cleanup mCleanup;
|
||||
};
|
||||
|
||||
TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
TEST_F(BackendTest, VertexBufferUpdate) {
|
||||
const bool largeBuffers = false;
|
||||
|
||||
// If updateIndices is true, then even-numbered triangles will have their indices set to
|
||||
@@ -112,15 +90,31 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
// executeCommands().
|
||||
{
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Shader shader = createShader();
|
||||
// Create a program.
|
||||
filamat::DescriptorSets descriptors;
|
||||
descriptors[1] = { { "Params",
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, 0 }, {} } };
|
||||
ShaderGenerator shaderGen(
|
||||
vertex, fragment, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(1, {{ "Params", DescriptorType::UNIFORM_BUFFER, 0 }});
|
||||
auto program = api.createProgram(std::move(p));
|
||||
|
||||
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// To test large buffers (which exercise a different code path) create an extra large
|
||||
// buffer. Only the first 3 vertices will be used.
|
||||
@@ -134,29 +128,38 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
||||
state.program = program;
|
||||
state.pipelineLayout.setLayout[1] = { descriptorSetLayout };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
// Create a uniform buffer.
|
||||
// We use STATIC here, even though the buffer is updated, to force the Metal backend to use
|
||||
// a GPU buffer, which is more interesting to test.
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams) + 64,
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
// We use STATIC here, even though the buffer is updated, to force the Metal backend to use a
|
||||
// GPU buffer, which is more interesting to test.
|
||||
auto ubuffer = api.createBufferObject(sizeof(MaterialParams) + 64,
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
|
||||
shader.bindUniform<MaterialParams>(api, ubuffer, kBindingConfig);
|
||||
api.updateDescriptorSetBuffer(descriptorSet, 0, ubuffer, 0, sizeof(MaterialParams) + 64);
|
||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
||||
|
||||
api.startCapture(0);
|
||||
|
||||
// Upload the uniform, but with an offset to accommodate the padding in the shader's
|
||||
// uniform definition.
|
||||
shader.uploadUniform(api, ubuffer, kBindingConfig, MaterialParams{
|
||||
.color = { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
.offset = { 0.0f, 0.0f, 0.0f, 0.0f }
|
||||
});
|
||||
// Upload uniforms.
|
||||
{
|
||||
MaterialParams params {
|
||||
.color = { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
.offset = { 0.0f, 0.0f, 0.0f, 0.0f }
|
||||
};
|
||||
auto* tmp = new MaterialParams(params);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
auto* sp = (MaterialParams*) buffer;
|
||||
delete sp;
|
||||
};
|
||||
BufferDescriptor bd(tmp, sizeof(MaterialParams), cb);
|
||||
api.updateBufferObject(ubuffer, std::move(bd), 64);
|
||||
}
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
@@ -199,6 +202,13 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
api.endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyBufferObject(ubuffer);
|
||||
api.destroyRenderTarget(defaultRenderTarget);
|
||||
}
|
||||
|
||||
executeCommands();
|
||||
@@ -206,38 +216,62 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
|
||||
// This test renders two triangles in two separate draw calls. Between the draw calls, a uniform
|
||||
// buffer object is partially updated.
|
||||
TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
TEST_F(BackendTest, BufferObjectUpdateWithOffset) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
Shader shader = createShader();
|
||||
filamat::DescriptorSets descriptors;
|
||||
descriptors[1] = { { "Params",
|
||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, 0 }, {} } };
|
||||
ShaderGenerator shaderGen(
|
||||
vertex, fragment, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(1, {{ "Params", DescriptorType::UNIFORM_BUFFER, 0 }});
|
||||
auto program = api.createProgram(std::move(p));
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
|
||||
// Create a uniform buffer.
|
||||
// We use STATIC here, even though the buffer is updated, to force the Metal backend to use a
|
||||
// GPU buffer, which is more interesting to test.
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams) + 64,
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
auto ubuffer = api.createBufferObject(sizeof(MaterialParams) + 64,
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
|
||||
shader.bindUniform<MaterialParams>(api, ubuffer, kBindingConfig);
|
||||
api.updateDescriptorSetBuffer(descriptorSet, 0, ubuffer, 0, sizeof(MaterialParams) + 64);
|
||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
||||
|
||||
// Create a render target.
|
||||
auto colorTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT));
|
||||
auto renderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR0, 512, 512, 1, 0, {{colorTexture}}, {}, {}));
|
||||
auto colorTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT);
|
||||
auto renderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR0, 512, 512, 1, 0, {{colorTexture}}, {}, {});
|
||||
|
||||
// Upload uniforms for the first triangle.
|
||||
// Upload the uniform, but with an offset to accommodate the padding in the shader's
|
||||
// uniform definition.
|
||||
shader.uploadUniform(api, ubuffer, kBindingConfig, MaterialParams{
|
||||
{
|
||||
MaterialParams params {
|
||||
.color = { 1.0f, 0.0f, 0.5f, 1.0f },
|
||||
.offset = { 0.0f, 0.0f, 0.0f, 0.0f }
|
||||
});
|
||||
};
|
||||
auto* tmp = new MaterialParams(params);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
auto* sp = (MaterialParams*) buffer;
|
||||
delete sp;
|
||||
};
|
||||
BufferDescriptor bd(tmp, sizeof(MaterialParams), cb);
|
||||
api.updateBufferObject(ubuffer, std::move(bd), 64);
|
||||
}
|
||||
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
@@ -246,27 +280,29 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.viewport.height = 512;
|
||||
params.viewport.width = 512;
|
||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
||||
renderTarget, swapChain, shader.getProgram(), params);
|
||||
renderTriangle({{ DescriptorSetLayoutHandle{}, descriptorSetLayout }},
|
||||
renderTarget, swapChain, program, params);
|
||||
|
||||
// Upload uniforms for the second triangle. To test partial buffer updates, we'll only update
|
||||
// color.b, color.a, offset.x, and offset.y.
|
||||
shader.uploadUniform(api, ubuffer, UniformBindingConfig{
|
||||
.dataSize = sizeof(std::array<float, 4>),
|
||||
.bufferSize = kBindingConfig.bufferSize,
|
||||
.byteOffset = *kBindingConfig.byteOffset + offsetof(MaterialParams, color.b),
|
||||
},
|
||||
std::array<float, 4>{
|
||||
// color.b, color.a
|
||||
1.0f, 1.0f,
|
||||
// offset.x, offset.y
|
||||
0.5f, 0.5f }
|
||||
);
|
||||
{
|
||||
MaterialParams params {
|
||||
.color = { 1.0f, 0.0f, 1.0f, 1.0f },
|
||||
.offset = { 0.5f, 0.5f, 0.0f, 0.0f }
|
||||
};
|
||||
auto* tmp = new MaterialParams(params);
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
auto* sp = (MaterialParams*) ((char*)buffer - offsetof(MaterialParams, color.b));
|
||||
delete sp;
|
||||
};
|
||||
BufferDescriptor bd((char*)tmp + offsetof(MaterialParams, color.b), sizeof(float) * 4, cb);
|
||||
api.updateBufferObject(ubuffer, std::move(bd), 64 + offsetof(MaterialParams, color.b));
|
||||
}
|
||||
|
||||
params.flags.clear = TargetBufferFlags::NONE;
|
||||
params.flags.discardStart = TargetBufferFlags::NONE;
|
||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
||||
renderTarget, swapChain, shader.getProgram(), params);
|
||||
renderTriangle({{ DescriptorSetLayoutHandle{}, descriptorSetLayout }},
|
||||
renderTarget, swapChain, program, params);
|
||||
|
||||
static const uint32_t expectedHash = 91322442;
|
||||
readPixelsAndAssertHash(
|
||||
@@ -276,6 +312,14 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyBufferObject(ubuffer);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
api.destroyTexture(colorTexture);
|
||||
|
||||
// This ensures all driver commands have finished before exiting the test.
|
||||
api.finish();
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
@@ -25,14 +23,13 @@ namespace test {
|
||||
|
||||
TEST_F(BackendTest, FrameScheduledCallback) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a SwapChain.
|
||||
// In order for the frameScheduledCallback to be called, this must be a real SwapChain (not
|
||||
// headless) so we obtain a drawable.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
Handle<HwRenderTarget> renderTarget = api.createDefaultRenderTarget();
|
||||
|
||||
int callbackCountA = 0;
|
||||
api.setFrameScheduledCallback(swapChain, nullptr, [&callbackCountA](PresentCallable callable) {
|
||||
@@ -82,10 +79,9 @@ TEST_F(BackendTest, FrameScheduledCallback) {
|
||||
|
||||
TEST_F(BackendTest, FrameCompletedCallback) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a SwapChain.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
|
||||
int callbackCountA = 0;
|
||||
api.setFrameCompletedCallback(swapChain, nullptr,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -130,13 +129,12 @@ static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt) {
|
||||
// backend's readPixels does not work correctly with textures that have image data uploaded.
|
||||
TEST_F(BackendTest, FeedbackLoops) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
@@ -157,10 +155,10 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
{ "test_tex", DescriptorType::SAMPLER, 0 },
|
||||
{ "Params", DescriptorType::UNIFORM_BUFFER, 1 }
|
||||
});
|
||||
program = cleanup.add(api.createProgram(std::move(prog)));
|
||||
program = api.createProgram(std::move(prog));
|
||||
}
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
@@ -170,27 +168,27 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 1,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
|
||||
TrianglePrimitive const triangle(getDriverApi());
|
||||
|
||||
// Create a texture.
|
||||
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
Handle<HwTexture> const texture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kTexFormat, 1, kTexWidth, kTexHeight, 1, usage));
|
||||
Handle<HwTexture> const texture = api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kTexFormat, 1, kTexWidth, kTexHeight, 1, usage);
|
||||
|
||||
// Create ubo
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
|
||||
// Create a RenderTarget for each miplevel.
|
||||
Handle<HwRenderTarget> renderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
slog.i << "Level " << int(level) << ": " <<
|
||||
(kTexWidth >> level) << "x" << (kTexHeight >> level) << io::endl;
|
||||
renderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kTexWidth >> level, kTexHeight >> level, 1, 0, { texture, level, 0 }, {}, {}));
|
||||
renderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kTexWidth >> level, kTexHeight >> level, 1, 0, { texture, level, 0 }, {}, {});
|
||||
}
|
||||
|
||||
// Fill the base level of the texture with interesting colors.
|
||||
@@ -228,13 +226,12 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
state.rasterState.disableBlending();
|
||||
for (int targetLevel = 1; targetLevel < kNumLevels; targetLevel++) {
|
||||
Cleanup passCleanup(api);
|
||||
const uint32_t sourceLevel = targetLevel - 1;
|
||||
params.viewport.width = kTexWidth >> targetLevel;
|
||||
params.viewport.height = kTexHeight >> targetLevel;
|
||||
|
||||
auto textureView = passCleanup.add(api.createTextureView(texture, sourceLevel, 1));
|
||||
DescriptorSetHandle descriptorSet = passCleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
auto textureView = api.createTextureView(texture, sourceLevel, 1);
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
api.updateDescriptorSetTexture(descriptorSet, 0, textureView, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
||||
@@ -250,6 +247,8 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
api.beginRenderPass(renderTargets[targetLevel], params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
api.destroyTexture(textureView);
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
}
|
||||
|
||||
// Upsample passes
|
||||
@@ -257,13 +256,12 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
state.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
state.rasterState.blendFunctionDstRGB = BlendFunction::ONE;
|
||||
for (int targetLevel = kNumLevels - 2; targetLevel >= 0; targetLevel--) {
|
||||
Cleanup passCleanup(api);
|
||||
const uint32_t sourceLevel = targetLevel + 1;
|
||||
params.viewport.width = kTexWidth >> targetLevel;
|
||||
params.viewport.height = kTexHeight >> targetLevel;
|
||||
|
||||
auto textureView = passCleanup.add(api.createTextureView(texture, sourceLevel, 1));
|
||||
DescriptorSetHandle descriptorSet = passCleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
auto textureView = api.createTextureView(texture, sourceLevel, 1);
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
api.updateDescriptorSetTexture(descriptorSet, 0, textureView, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
||||
@@ -279,6 +277,8 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
api.beginRenderPass(renderTargets[targetLevel], params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
api.destroyTexture(textureView);
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
}
|
||||
|
||||
// Read back the render target corresponding to the base level.
|
||||
@@ -296,6 +296,15 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
}
|
||||
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyTexture(texture);
|
||||
api.destroyBufferObject(ubuffer);
|
||||
for (auto rt : renderTargets) {
|
||||
api.destroyRenderTarget(rt);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t expected = 0x70695aa1;
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "BackendTestUtils.h"
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
#include "BackendTestUtils.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
@@ -296,12 +295,10 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
for (const auto& t : testCases) {
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
|
||||
@@ -318,21 +315,21 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
prog.descriptorBindings(1, {{"test_tex", DescriptorType::SAMPLER, 0}});
|
||||
|
||||
ProgramHandle const program = cleanup.add(api.createProgram(std::move(prog)));
|
||||
ProgramHandle const program = api.createProgram(std::move(prog));
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
// Create a Texture.
|
||||
auto usage = TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE;
|
||||
Handle<HwTexture> const texture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
t.textureFormat, 1, 512, 512, 1u, usage));
|
||||
Handle<HwTexture> const texture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
t.textureFormat, 1, 512, 512, 1u, usage);
|
||||
|
||||
// Upload some pixel data.
|
||||
if (t.uploadSubregions) {
|
||||
@@ -362,6 +359,13 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(defaultRenderTarget);
|
||||
api.destroyTexture(texture);
|
||||
}
|
||||
|
||||
api.finish();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -61,28 +60,25 @@ using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
TEST_F(BackendTest, MRT) {
|
||||
DriverApi& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
auto swapChain = createSwapChain();
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
auto program = cleanup.add(api.createProgram(std::move(p)));
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
auto program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
TrianglePrimitive triangle(getDriverApi());
|
||||
|
||||
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
auto defaultRenderTarget = getDriverApi().createDefaultRenderTarget(0);
|
||||
|
||||
// Create two Textures.
|
||||
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
Handle<HwTexture> textureA = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> textureA = getDriverApi().createTexture(
|
||||
SamplerType::SAMPLER_2D, // target
|
||||
1, // levels
|
||||
TextureFormat::RGBA8, // format
|
||||
@@ -90,8 +86,8 @@ TEST_F(BackendTest, MRT) {
|
||||
512, // width
|
||||
512, // height
|
||||
1, // depth
|
||||
usage)); // usage
|
||||
Handle<HwTexture> textureB = cleanup.add(api.createTexture(
|
||||
usage); // usage
|
||||
Handle<HwTexture> textureB = getDriverApi().createTexture(
|
||||
SamplerType::SAMPLER_2D, // target
|
||||
1, // levels
|
||||
TextureFormat::RGBA8, // format
|
||||
@@ -99,10 +95,10 @@ TEST_F(BackendTest, MRT) {
|
||||
512, // width
|
||||
512, // height
|
||||
1, // depth
|
||||
usage)); // usage
|
||||
usage); // usage
|
||||
|
||||
// Create a RenderTarget with two attachments.
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> renderTarget = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR0 | TargetBufferFlags::COLOR1,
|
||||
// The width and height must match the width and height of the respective mip
|
||||
// level (at least for OpenGL).
|
||||
@@ -112,7 +108,7 @@ TEST_F(BackendTest, MRT) {
|
||||
0, // layerCount
|
||||
{{textureA },{textureB }}, // color
|
||||
{}, // depth
|
||||
{})); // stencil
|
||||
{}); // stencil
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -128,21 +124,25 @@ TEST_F(BackendTest, MRT) {
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
api.startCapture(0);
|
||||
getDriverApi().startCapture(0);
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
getDriverApi().beginFrame(0, 0, 0);
|
||||
|
||||
// Draw a triangle.
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
getDriverApi().beginRenderPass(renderTarget, params);
|
||||
getDriverApi().draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
getDriverApi().endRenderPass();
|
||||
|
||||
api.flush();
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
getDriverApi().flush();
|
||||
getDriverApi().commit(swapChain);
|
||||
getDriverApi().endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
getDriverApi().stopCapture(0);
|
||||
|
||||
getDriverApi().destroyProgram(program);
|
||||
getDriverApi().destroySwapChain(swapChain);
|
||||
getDriverApi().destroyRenderTarget(defaultRenderTarget);
|
||||
}
|
||||
|
||||
executeCommands();
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "BackendTestUtils.h"
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
#include "BackendTestUtils.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
@@ -79,13 +78,12 @@ using namespace filament::backend;
|
||||
TEST_F(BackendTest, TextureViewLod) {
|
||||
auto& api = getDriverApi();
|
||||
api.startCapture(0);
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program that draws only white.
|
||||
@@ -94,7 +92,7 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
ShaderGenerator shaderGen(vertex, whiteFragment, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(0, {{"backend_test_sib_tex", DescriptorType::SAMPLER, 0}});
|
||||
whiteProgram = cleanup.add(api.createProgram(std::move(p)));
|
||||
whiteProgram = api.createProgram(std::move(p));
|
||||
}
|
||||
|
||||
// Create a program that samples a texture.
|
||||
@@ -108,19 +106,19 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(0, {{"backend_test_sib_tex", DescriptorType::SAMPLER, 0}});
|
||||
textureProgram = cleanup.add(api.createProgram(std::move(p)));
|
||||
textureProgram = api.createProgram(std::move(p));
|
||||
}
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet[2];
|
||||
descriptorSet[0] = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
descriptorSet[1] = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
descriptorSet[0] = api.createDescriptorSet(descriptorSetLayout);
|
||||
descriptorSet[1] = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
// Create a texture that has 4 mip levels. Each level is a different color.
|
||||
// Level 0: 128x128 (red)
|
||||
@@ -129,9 +127,9 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
// Level 3: 16x16 (yellow)
|
||||
const size_t kTextureSize = 128;
|
||||
const size_t kMipLevels = 4;
|
||||
Handle<HwTexture> texture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, kMipLevels,
|
||||
Handle<HwTexture> texture = api.createTexture(SamplerType::SAMPLER_2D, kMipLevels,
|
||||
TextureFormat::RGBA8, 1, kTextureSize, kTextureSize, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT | TextureUsage::UPLOADABLE));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT | TextureUsage::UPLOADABLE);
|
||||
|
||||
// Create image data.
|
||||
auto pixelFormat = PixelDataFormat::RGBA;
|
||||
@@ -165,13 +163,13 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
// Level 1: 64x64 (green) <-- base
|
||||
// Level 2: 32x32 (blue) <--- white triangle rendered
|
||||
// Level 3: 16x16 (yellow) <-- max
|
||||
auto texture13 = cleanup.add(api.createTextureView(texture, 1, 3));
|
||||
auto texture13 = api.createTextureView(texture, 1, 3);
|
||||
|
||||
// Render a white triangle into level 2.
|
||||
// We specify mip level 2, because minMaxLevels has no effect when rendering into a texture.
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> renderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, 32, 32, 1, 0,
|
||||
{texture, 2 /* level */, 0 /* layer */}, {}, {}));
|
||||
{texture, 2 /* level */, 0 /* layer */}, {}, {});
|
||||
{
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -187,7 +185,7 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
api.endRenderPass();
|
||||
}
|
||||
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -219,7 +217,7 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
api.endRenderPass();
|
||||
|
||||
// Adjust the base mip to 2.
|
||||
auto texture22 = cleanup.add(api.createTextureView(texture, 2, 2));
|
||||
auto texture22 = api.createTextureView(texture, 2, 2);
|
||||
|
||||
api.updateDescriptorSetTexture(descriptorSet[1], 0, texture22, {
|
||||
.filterMag = SamplerMagFilter::NEAREST,
|
||||
@@ -246,6 +244,18 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
api.endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Cleanup.
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
api.destroyDescriptorSet(descriptorSet[0]);
|
||||
api.destroyDescriptorSet(descriptorSet[1]);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyTexture(texture);
|
||||
api.destroyTexture(texture13);
|
||||
api.destroyTexture(texture22);
|
||||
api.destroyProgram(whiteProgram);
|
||||
api.destroyProgram(textureProgram);
|
||||
}
|
||||
|
||||
api.finish();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -71,20 +70,18 @@ TEST_F(BackendTest, MissingRequiredAttributes) {
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
DriverApi& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
auto swapChain = createSwapChain();
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
auto program = cleanup.add(api.createProgram(std::move(p)));
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
auto program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
auto defaultRenderTarget = getDriverApi().createDefaultRenderTarget(0);
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
TrianglePrimitive triangle(getDriverApi());
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -100,21 +97,25 @@ TEST_F(BackendTest, MissingRequiredAttributes) {
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
api.startCapture(0);
|
||||
getDriverApi().startCapture(0);
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
getDriverApi().beginFrame(0, 0, 0);
|
||||
|
||||
// Render a triangle.
|
||||
api.beginRenderPass(defaultRenderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
getDriverApi().beginRenderPass(defaultRenderTarget, params);
|
||||
getDriverApi().draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
getDriverApi().endRenderPass();
|
||||
|
||||
api.flush();
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
getDriverApi().flush();
|
||||
getDriverApi().commit(swapChain);
|
||||
getDriverApi().endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
getDriverApi().stopCapture(0);
|
||||
|
||||
getDriverApi().destroyProgram(program);
|
||||
getDriverApi().destroySwapChain(swapChain);
|
||||
getDriverApi().destroyRenderTarget(defaultRenderTarget);
|
||||
}
|
||||
|
||||
executeCommands();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -81,21 +80,20 @@ TEST_F(BackendTest, PushConstants) {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
api.startCapture(0);
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
ProgramHandle program = cleanup.add(api.createProgram(std::move(p)));
|
||||
ProgramHandle program = api.createProgram(std::move(p));
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
Handle<HwRenderTarget> renderTarget = api.createDefaultRenderTarget();
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
@@ -152,6 +150,10 @@ TEST_F(BackendTest, PushConstants) {
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Cleanup.
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "BackendTestUtils.h"
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
#include "BackendTestUtils.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
|
||||
@@ -237,20 +236,17 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
|
||||
TestCase const testCases[] = { t0, t2, t3, t4, t5, t6, t7, t8 };
|
||||
|
||||
DriverApi& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create programs.
|
||||
Handle<HwProgram> programFloat, programUint;
|
||||
{
|
||||
ShaderGenerator shaderGen(vertex, fragmentFloat, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
programFloat = cleanup.add(api.createProgram(std::move(p)));
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
programFloat = getDriverApi().createProgram(std::move(p));
|
||||
}
|
||||
{
|
||||
ShaderGenerator shaderGen(vertex, fragmentUint, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
programUint = cleanup.add(api.createProgram(std::move(p)));
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
programUint = getDriverApi().createProgram(std::move(p));
|
||||
}
|
||||
|
||||
|
||||
@@ -259,35 +255,35 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
Handle<HwSwapChain> swapChain;
|
||||
if (t.useDefaultRT) {
|
||||
swapChain = cleanup.add(createSwapChain());
|
||||
swapChain = createSwapChain();
|
||||
} else {
|
||||
swapChain = cleanup.add(api.createSwapChainHeadless(t.getRenderTargetSize(),
|
||||
t.getRenderTargetSize(), 0));
|
||||
swapChain = getDriverApi().createSwapChainHeadless(t.getRenderTargetSize(),
|
||||
t.getRenderTargetSize(), 0);
|
||||
}
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a Texture and RenderTarget to render into.
|
||||
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
Handle<HwTexture> const texture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D,
|
||||
Handle<HwTexture> const texture = getDriverApi().createTexture(SamplerType::SAMPLER_2D,
|
||||
t.mipLevels, t.textureFormat, 1, renderTargetBaseSize, renderTargetBaseSize, 1,
|
||||
usage));
|
||||
usage);
|
||||
|
||||
Handle<HwRenderTarget> renderTarget;
|
||||
if (t.useDefaultRT) {
|
||||
// The width and height must match the width and height of the respective mip
|
||||
// level (at least for OpenGL).
|
||||
renderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
renderTarget = getDriverApi().createDefaultRenderTarget();
|
||||
} else {
|
||||
// The width and height must match the width and height of the respective mip
|
||||
// level (at least for OpenGL).
|
||||
renderTarget = cleanup.add(api.createRenderTarget(
|
||||
renderTarget = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR, t.getRenderTargetSize(),
|
||||
t.getRenderTargetSize(), t.samples, 0, {{ texture, uint8_t(t.mipLevel) }}, {},
|
||||
{}));
|
||||
{});
|
||||
}
|
||||
|
||||
TrianglePrimitive const triangle(api);
|
||||
TrianglePrimitive const triangle(getDriverApi());
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -298,11 +294,11 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
params.viewport.height = t.getRenderTargetSize();
|
||||
params.viewport.width = t.getRenderTargetSize();
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
getDriverApi().beginFrame(0, 0, 0);
|
||||
|
||||
// Render a white triangle over blue.
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
getDriverApi().beginRenderPass(renderTarget, params);
|
||||
|
||||
PipelineState state;
|
||||
state.program = programFloat;
|
||||
@@ -313,21 +309,21 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
getDriverApi().draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
|
||||
api.endRenderPass();
|
||||
getDriverApi().endRenderPass();
|
||||
|
||||
if (t.mipLevel > 0) {
|
||||
Cleanup localCleanup(api);
|
||||
// Render red to the first mip level to check that the backend is actually reading the
|
||||
// correct mip.
|
||||
RenderPassParams p = params;
|
||||
Handle<HwRenderTarget> mipLevelOneRT = localCleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> mipLevelOneRT = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR, renderTargetBaseSize, renderTargetBaseSize, 1, 0,
|
||||
{{ texture }}, {}, {}));
|
||||
{{ texture }}, {}, {});
|
||||
p.clearColor = {1.f, 0.f, 0.f, 1.f};
|
||||
api.beginRenderPass(mipLevelOneRT, p);
|
||||
api.endRenderPass();
|
||||
getDriverApi().beginRenderPass(mipLevelOneRT, p);
|
||||
getDriverApi().endRenderPass();
|
||||
getDriverApi().destroyRenderTarget(mipLevelOneRT);
|
||||
}
|
||||
|
||||
// Read pixels.
|
||||
@@ -351,19 +347,26 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
free(buffer);
|
||||
}, (void*) &t);
|
||||
|
||||
api.readPixels(renderTarget, t.readRect.x, t.readRect.y, t.readRect.width,
|
||||
getDriverApi().readPixels(renderTarget, t.readRect.x, t.readRect.y, t.readRect.width,
|
||||
t.readRect.height, std::move(descriptor));
|
||||
|
||||
// Now render red over what was just rendered. This ensures that readPixels captures the
|
||||
// state of rendering between render passes.
|
||||
params.clearColor = {1.f, 0.f, 0.f, 1.f};
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
api.endRenderPass();
|
||||
getDriverApi().beginRenderPass(renderTarget, params);
|
||||
getDriverApi().endRenderPass();
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
getDriverApi().commit(swapChain);
|
||||
getDriverApi().endFrame(0);
|
||||
|
||||
getDriverApi().destroySwapChain(swapChain);
|
||||
getDriverApi().destroyRenderTarget(renderTarget);
|
||||
getDriverApi().destroyTexture(texture);
|
||||
}
|
||||
|
||||
getDriverApi().destroyProgram(programFloat);
|
||||
getDriverApi().destroyProgram(programUint);
|
||||
|
||||
// This ensures all driver commands have finished before exiting the test.
|
||||
flushAndWait();
|
||||
}
|
||||
@@ -372,21 +375,18 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
const size_t renderTargetSize = 2000;
|
||||
const int iterationCount = 100;
|
||||
|
||||
DriverApi& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(renderTargetSize, renderTargetSize, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
auto swapChain = getDriverApi().createSwapChainHeadless(renderTargetSize, renderTargetSize, 0);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(vertex, fragmentFloat, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
auto program = cleanup.add(api.createProgram(std::move(p)));
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
auto program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
// Create a Texture and RenderTarget to render into.
|
||||
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
Handle<HwTexture> texture = cleanup.add(api.createTexture(
|
||||
Handle<HwTexture> texture = getDriverApi().createTexture(
|
||||
SamplerType::SAMPLER_2D, // target
|
||||
1, // levels
|
||||
TextureFormat::RGBA8, // format
|
||||
@@ -394,9 +394,9 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
renderTargetSize, // width
|
||||
renderTargetSize, // height
|
||||
1, // depth
|
||||
usage)); // usage
|
||||
usage); // usage
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> renderTarget = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR,
|
||||
renderTargetSize, // width
|
||||
renderTargetSize, // height
|
||||
@@ -404,9 +404,9 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
0, // layerCount
|
||||
{{ texture }}, // color
|
||||
{}, // depth
|
||||
{})); // stencil
|
||||
{}); // stencil
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
TrianglePrimitive triangle(getDriverApi());
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -433,13 +433,13 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
printf("Executing test %d / %d\n", iteration, iterationCount);
|
||||
}
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
getDriverApi().makeCurrent(swapChain, swapChain);
|
||||
getDriverApi().beginFrame(0, 0, 0);
|
||||
|
||||
// Render some content, just so we don't read back uninitialized data.
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
getDriverApi().beginRenderPass(renderTarget, params);
|
||||
getDriverApi().draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
getDriverApi().endRenderPass();
|
||||
|
||||
PixelBufferDescriptor descriptor(buffer, renderTargetSize * renderTargetSize * 4,
|
||||
PixelDataFormat::RGBA, PixelDataType::UBYTE, 1, 0, 0, renderTargetSize,
|
||||
@@ -448,9 +448,9 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
test->readPixelsFinished = true;
|
||||
}, this);
|
||||
|
||||
api.readPixels(renderTarget, 0, 0, renderTargetSize, renderTargetSize, std::move(descriptor));
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
getDriverApi().readPixels(renderTarget, 0, 0, renderTargetSize, renderTargetSize, std::move(descriptor));
|
||||
getDriverApi().commit(swapChain);
|
||||
getDriverApi().endFrame(0);
|
||||
|
||||
flushAndWait();
|
||||
getDriver().purge();
|
||||
@@ -460,7 +460,11 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
|
||||
free(buffer);
|
||||
|
||||
api.finish();
|
||||
getDriverApi().destroyProgram(program);
|
||||
getDriverApi().destroySwapChain(swapChain);
|
||||
getDriverApi().destroyRenderTarget(renderTarget);
|
||||
getDriverApi().destroyTexture(texture);
|
||||
getDriverApi().finish();
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -67,11 +66,10 @@ using namespace filament::backend;
|
||||
// Rendering an external image without setting any data should not crash.
|
||||
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
|
||||
SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH, false };
|
||||
@@ -84,22 +82,22 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(1, {{"test_tex", DescriptorType::SAMPLER, 0}});
|
||||
backend::Handle<HwProgram> program = cleanup.add(api.createProgram(std::move(p)));
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
backend::Handle<HwProgram> program = api.createProgram(std::move(p));
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a texture that will be backed by an external image.
|
||||
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
const NativeView& view = getNativeView();
|
||||
backend::Handle<HwTexture> texture = cleanup.add(api.createTexture(
|
||||
backend::Handle<HwTexture> texture = api.createTexture(
|
||||
SamplerType::SAMPLER_EXTERNAL, // target
|
||||
1, // levels
|
||||
TextureFormat::RGBA8, // format
|
||||
@@ -107,7 +105,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
view.width, // width
|
||||
view.height, // height
|
||||
1, // depth
|
||||
usage)); // usage
|
||||
usage); // usage
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
@@ -142,6 +140,15 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Delete our resources.
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyTexture(texture);
|
||||
|
||||
// Destroy frame resources.
|
||||
api.destroyProgram(program);
|
||||
api.destroyRenderTarget(defaultRenderTarget);
|
||||
|
||||
api.finish();
|
||||
|
||||
executeCommands();
|
||||
@@ -149,11 +156,10 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
|
||||
TEST_F(BackendTest, RenderExternalImage) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0,
|
||||
SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH, false };
|
||||
@@ -166,18 +172,18 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(api);
|
||||
p.descriptorBindings(1, {{"test_tex", DescriptorType::SAMPLER, 0}});
|
||||
auto program = cleanup.add(api.createProgram(std::move(p)));
|
||||
auto program = api.createProgram(std::move(p));
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}}));
|
||||
}}});
|
||||
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0));
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// require users to create two Filament textures and have two material parameters
|
||||
// add a "plane" parameter to setExternalImage
|
||||
@@ -221,8 +227,8 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
|
||||
api.setupExternalImage(pixBuffer);
|
||||
backend::Handle<HwTexture> texture =
|
||||
cleanup.add(api.createTextureExternalImage(SamplerType::SAMPLER_EXTERNAL,
|
||||
TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer));
|
||||
api.createTextureExternalImage(SamplerType::SAMPLER_EXTERNAL,
|
||||
TextureFormat::RGBA8, 1024, 1024, usage, pixBuffer);
|
||||
|
||||
// We're now free to release the buffer.
|
||||
CVBufferRelease(pixBuffer);
|
||||
@@ -263,6 +269,15 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Delete our resources.
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyTexture(texture);
|
||||
|
||||
// Destroy frame resources.
|
||||
api.destroyProgram(program);
|
||||
api.destroyRenderTarget(defaultRenderTarget);
|
||||
|
||||
api.finish();
|
||||
|
||||
executeCommands();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -56,7 +55,6 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
constexpr int kSrcRtHeight = 384;
|
||||
|
||||
api.startCapture(0);
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// color texture (mip level 1) 512x512 depth texture (mip level 0) 512x512
|
||||
// +----------------------------------------+ +------------------------------------------+
|
||||
@@ -82,21 +80,21 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
ProgramHandle program = cleanup.add(api.createProgram(std::move(p)));
|
||||
ProgramHandle program = api.createProgram(std::move(p));
|
||||
|
||||
// Create source color and depth textures.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, kNumLevels,
|
||||
Handle<HwTexture> srcTexture = api.createTexture(SamplerType::SAMPLER_2D, kNumLevels,
|
||||
kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> depthTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
Handle<HwTexture> depthTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH16, 1, 512, 512, 1,
|
||||
TextureUsage::DEPTH_ATTACHMENT));
|
||||
TextureUsage::DEPTH_ATTACHMENT);
|
||||
|
||||
// Render into the bottom-left quarter of the texture.
|
||||
Viewport srcRect = {
|
||||
@@ -114,13 +112,13 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
|
||||
// We purposely set the render target width and height to smaller than the texture, to check
|
||||
// that this case is handled correctly.
|
||||
Handle<HwRenderTarget> srcRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1, 0,
|
||||
{srcTexture, kSrcLevel, 0}, {depthTexture, 0, 0}, {}));
|
||||
{srcTexture, kSrcLevel, 0}, {depthTexture, 0, 0}, {});
|
||||
|
||||
Handle<HwRenderTarget> fullRenderTarget = cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
Handle<HwRenderTarget> fullRenderTarget = api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexHeight >> kSrcLevel, kSrcTexWidth >> kSrcLevel, 1, 0,
|
||||
{srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
{srcTexture, kSrcLevel, 0}, {}, {});
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
@@ -152,6 +150,11 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
api.endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
@@ -166,24 +169,23 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
api.startCapture(0);
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
ProgramHandle program = cleanup.add(api.createProgram(std::move(p)));
|
||||
ProgramHandle program = api.createProgram(std::move(p));
|
||||
|
||||
// Create a source color textures.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
Handle<HwTexture> srcTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
|
||||
// Render into the bottom-left quarter of the texture, checking 3 special cases.
|
||||
// 1. negative viewport left/bottom
|
||||
@@ -205,9 +207,9 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
Viewport scissor = {0, 0, (uint32_t)std::numeric_limits<int32_t>::max(),
|
||||
(uint32_t)std::numeric_limits<int32_t>::max()};
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createRenderTarget(
|
||||
Handle<HwRenderTarget> renderTarget = api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, 512, 512, 1, 0,
|
||||
{srcTexture, 0, 0}, {}, {}));
|
||||
{srcTexture, 0, 0}, {}, {});
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
@@ -247,6 +249,11 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
api.endFrame(0);
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -64,23 +63,20 @@ namespace test {
|
||||
class BasicStencilBufferTest : public BackendTest {
|
||||
public:
|
||||
|
||||
Handle<HwSwapChain> mSwapChain;
|
||||
ProgramHandle mProgram;
|
||||
Cleanup mCleanup;
|
||||
|
||||
BasicStencilBufferTest() : mCleanup(getDriverApi()) {}
|
||||
Handle<HwSwapChain> swapChain;
|
||||
ProgramHandle program;
|
||||
|
||||
void SetUp() override {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
mSwapChain = mCleanup.add(createSwapChain());
|
||||
api.makeCurrent(mSwapChain, mSwapChain);
|
||||
swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
mProgram = mCleanup.add(api.createProgram(std::move(p)));
|
||||
program = api.createProgram(std::move(p));
|
||||
}
|
||||
|
||||
void RunTest(Handle<HwRenderTarget> renderTarget) {
|
||||
@@ -107,13 +103,13 @@ public:
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = mProgram;
|
||||
ps.program = program;
|
||||
ps.rasterState.colorWrite = false;
|
||||
ps.rasterState.depthWrite = false;
|
||||
ps.stencilState.stencilWrite = true;
|
||||
ps.stencilState.front.stencilOpDepthStencilPass = StencilOperation::INCR;
|
||||
|
||||
api.makeCurrent(mSwapChain, mSwapChain);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
@@ -133,27 +129,29 @@ public:
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
|
||||
api.commit(mSwapChain);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
auto& api = getDriverApi();
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
flushAndWait();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BasicStencilBufferTest, StencilBuffer) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create two textures: a color and a stencil, and an associated RenderTarget.
|
||||
auto colorTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT));
|
||||
auto stencilTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT));
|
||||
auto renderTarget = cleanup.add(api.createRenderTarget(
|
||||
auto colorTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT);
|
||||
auto stencilTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT);
|
||||
auto renderTarget = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1, 0,
|
||||
{{colorTexture}}, {}, {{stencilTexture}}));
|
||||
{{colorTexture}}, {}, {{stencilTexture}});
|
||||
|
||||
RunTest(renderTarget);
|
||||
|
||||
@@ -161,20 +159,23 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
|
||||
|
||||
flushAndWait();
|
||||
getDriver().purge();
|
||||
|
||||
api.destroyTexture(colorTexture);
|
||||
api.destroyTexture(stencilTexture);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create two textures: a color and a stencil, and an associated RenderTarget.
|
||||
auto colorTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT));
|
||||
auto depthStencilTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH24_STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT));
|
||||
auto renderTarget = cleanup.add(api.createRenderTarget(
|
||||
auto colorTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT);
|
||||
auto depthStencilTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH24_STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT);
|
||||
auto renderTarget = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1, 0,
|
||||
{{colorTexture}}, {depthStencilTexture}, {{depthStencilTexture}}));
|
||||
{{colorTexture}}, {depthStencilTexture}, {{depthStencilTexture}});
|
||||
|
||||
RunTest(renderTarget);
|
||||
|
||||
@@ -182,27 +183,30 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
||||
|
||||
flushAndWait();
|
||||
getDriver().purge();
|
||||
|
||||
api.destroyTexture(colorTexture);
|
||||
api.destroyTexture(depthStencilTexture);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create two textures: a single-sampled color and a MSAA stencil texture.
|
||||
// We also create two RenderTargets, one for each pass:
|
||||
// Pass 0: Render a triangle only into the MSAA stencil buffer.
|
||||
// Pass 1: Render a triangle into (an auto-created) MSAA color buffer using the stencil test.
|
||||
// Performs an auto-resolve on the color.
|
||||
auto colorTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE));
|
||||
auto depthStencilTextureMSAA = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH24_STENCIL8, 4, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT));
|
||||
auto renderTarget0 = cleanup.add(api.createRenderTarget(
|
||||
auto colorTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE);
|
||||
auto depthStencilTextureMSAA = api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH24_STENCIL8, 4, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT);
|
||||
auto renderTarget0 = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4, 0,
|
||||
{{}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA}));
|
||||
auto renderTarget1 = cleanup.add(api.createRenderTarget(
|
||||
{{}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA});
|
||||
auto renderTarget1 = getDriverApi().createRenderTarget(
|
||||
TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4, 0,
|
||||
{{colorTexture}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA}));
|
||||
{{colorTexture}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA});
|
||||
|
||||
api.startCapture(0);
|
||||
|
||||
@@ -226,13 +230,13 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = mProgram;
|
||||
ps.program = program;
|
||||
ps.rasterState.colorWrite = false;
|
||||
ps.rasterState.depthWrite = false;
|
||||
ps.stencilState.stencilWrite = true;
|
||||
ps.stencilState.front.stencilOpDepthStencilPass = StencilOperation::INCR;
|
||||
|
||||
api.makeCurrent(mSwapChain, mSwapChain);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
api.beginRenderPass(renderTarget0, params);
|
||||
@@ -254,7 +258,7 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
|
||||
api.commit(mSwapChain);
|
||||
api.commit(swapChain);
|
||||
api.stopCapture(0);
|
||||
api.endFrame(0);
|
||||
|
||||
@@ -262,6 +266,11 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
|
||||
flushAndWait();
|
||||
getDriver().purge();
|
||||
|
||||
api.destroyTexture(colorTexture);
|
||||
api.destroyTexture(depthStencilTextureMSAA);
|
||||
api.destroyRenderTarget(renderTarget0);
|
||||
api.destroyRenderTarget(renderTarget1);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <backend/BufferDescriptor.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -91,21 +90,9 @@ public:
|
||||
* @param name A string to identify this BufferObject
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this BufferObject for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this BufferObject
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the BufferObject and returns a pointer to it. After creation, the buffer
|
||||
* object is uninitialized. Use BufferObject::setBuffer() to initialize it.
|
||||
|
||||
@@ -64,8 +64,9 @@ class ColorSpace;
|
||||
* Performance
|
||||
* ===========
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* Ordering
|
||||
* ========
|
||||
@@ -154,9 +155,6 @@ 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.
|
||||
@@ -171,8 +169,6 @@ 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.
|
||||
@@ -185,8 +181,6 @@ 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.
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -62,17 +61,11 @@ UTILS_PUBLIC void builderMakeName(utils::CString& outName, const char* name, siz
|
||||
template <typename Builder>
|
||||
class UTILS_PUBLIC BuilderNameMixin {
|
||||
public:
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* name, size_t len) noexcept {
|
||||
builderMakeName(mName, name, len);
|
||||
return static_cast<Builder&>(*this);
|
||||
}
|
||||
|
||||
Builder& name(utils::StaticString const& name) noexcept {
|
||||
builderMakeName(mName, name.data(), name.size());
|
||||
return static_cast<Builder&>(*this);
|
||||
}
|
||||
|
||||
utils::CString const& getName() const noexcept { return mName; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <backend/BufferDescriptor.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -96,21 +95,9 @@ public:
|
||||
* @param name A string to identify this IndexBuffer
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this IndexBuffer for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this IndexBuffer
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the IndexBuffer object and returns a pointer to it. After creation, the index
|
||||
* buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer.
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
|
||||
@@ -83,21 +82,9 @@ public:
|
||||
* @param name A string to identify this InstanceBuffer
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this InstanceBuffer for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this InstanceBuffer
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the InstanceBuffer object and returns a pointer to it.
|
||||
*/
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
|
||||
@@ -76,21 +75,9 @@ public:
|
||||
* @param name A string to identify this MorphTargetBuffer
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this MorphTargetBuffer for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this MorphTargetBuffer
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the MorphTargetBuffer object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <filament/RenderableManager.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
|
||||
@@ -82,21 +81,9 @@ public:
|
||||
* @param name A string to identify this SkinningBuffer
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this SkinningBuffer for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this SkinningBuffer
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the SkinningBuffer object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <backend/CallbackHandler.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <math/mat3.h>
|
||||
|
||||
@@ -151,21 +150,9 @@ public:
|
||||
* @param name A string to identify this Stream
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this Stream for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this Stream
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the Stream object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -230,20 +229,8 @@ public:
|
||||
* @param name A string to identify this Texture
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this Texture for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this Texture
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Creates an external texture. The content must be set using setExternalImage().
|
||||
|
||||
@@ -68,21 +68,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,8 +79,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -108,8 +91,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -123,8 +104,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,8 +117,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -152,8 +129,6 @@ 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; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -175,8 +150,6 @@ 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;
|
||||
};
|
||||
@@ -221,8 +194,6 @@ 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;
|
||||
@@ -285,8 +256,6 @@ 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
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -171,21 +170,9 @@ public:
|
||||
* @param name A string to identify this VertexBuffer
|
||||
* @param len Length of name, should be less than or equal to 128
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use name(utils::StaticString const&) instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept;
|
||||
|
||||
/**
|
||||
* Associate an optional name with this VertexBuffer for debugging purposes.
|
||||
*
|
||||
* name will show in error messages and should be kept as short as possible.
|
||||
*
|
||||
* @param name A string literal to identify this VertexBuffer
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
Builder& name(utils::StaticString const& name) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the VertexBuffer object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -2306,11 +2306,36 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
|
||||
const FColorGrading* colorGrading, ColorGradingConfig const& colorGradingConfig,
|
||||
VignetteOptions const& vignetteOptions, uint32_t const width, uint32_t const height) noexcept {
|
||||
|
||||
auto& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterialInstance* const mi =
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, width, height);
|
||||
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);
|
||||
mi->commit(driver);
|
||||
|
||||
// load both variants
|
||||
material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||
material.getMaterial(mEngine, PostProcessVariant::TRANSLUCENT);
|
||||
}
|
||||
|
||||
void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
@@ -2341,9 +2366,6 @@ void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomRe
|
||||
}
|
||||
|
||||
void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
|
||||
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
|
||||
FEngine const& engine = mEngine;
|
||||
Handle<HwRenderPrimitive> const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive();
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
@@ -2465,14 +2487,22 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
|
||||
auto const& input = resources.getDescriptor(data.input);
|
||||
auto const& output = resources.getDescriptor(data.output);
|
||||
auto const& material = getPostProcessMaterial("colorGrading");
|
||||
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
auto& material = getPostProcessMaterial("colorGrading");
|
||||
FMaterialInstance* const mi =
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, output.width, output.height);
|
||||
PostProcessMaterial::getMaterialInstance(mEngine, material, variant);
|
||||
|
||||
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,
|
||||
@@ -2504,7 +2534,19 @@ 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,
|
||||
@@ -2512,9 +2554,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
float(vp.height) / input.height
|
||||
});
|
||||
|
||||
commitAndRenderFullScreenQuad(driver, out, mi,
|
||||
colorGradingConfig.translucent
|
||||
? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
|
||||
commitAndRenderFullScreenQuad(driver, out, mi, variant);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2652,70 +2692,11 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma);
|
||||
if (dirty) {
|
||||
ma->invalidate();
|
||||
// TODO: call Material::compile(), we can't do that now because it works only
|
||||
// TODO: call Material::compile(), we can't si 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,
|
||||
@@ -3039,7 +3020,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg, bool sourceHasLuminance,
|
||||
DynamicResolutionOptions dsrOptions, FrameGraphId<FrameGraphTexture> const input,
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept {
|
||||
filament::Viewport const&, FrameGraphTexture::Descriptor const& outDesc) noexcept {
|
||||
|
||||
struct QuadBlitData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
@@ -3055,7 +3036,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
.attachments = { .color = { data.output } },
|
||||
.clearFlags = TargetBufferFlags::DEPTH });
|
||||
},
|
||||
[this, vp, sourceHasLuminance](FrameGraphResources const& resources,
|
||||
[this, sourceHasLuminance](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
|
||||
@@ -3081,17 +3062,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
});
|
||||
|
||||
mi->setParameter("viewport", float4{
|
||||
float(vp.left) / inputDesc.width,
|
||||
float(vp.bottom) / inputDesc.height,
|
||||
float(vp.width) / inputDesc.width,
|
||||
float(vp.height) / inputDesc.height
|
||||
});
|
||||
|
||||
mi->setParameter("viewportInfo", float4{
|
||||
1.0f / inputDesc.width,
|
||||
1.0f / inputDesc.height,
|
||||
float(inputDesc.width),
|
||||
float(inputDesc.height)
|
||||
float(inputDesc.height),
|
||||
});
|
||||
|
||||
mi->commit(driver);
|
||||
|
||||
@@ -401,13 +401,6 @@ 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;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -52,10 +51,6 @@ BufferObject::Builder& BufferObject::Builder::name(const char* name, size_t cons
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
BufferObject::Builder& BufferObject::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
BufferObject* BufferObject::Builder::build(Engine& engine) {
|
||||
return downcast(engine).createBufferObject(*this);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
|
||||
namespace filament {
|
||||
@@ -580,11 +581,8 @@ static float3 luminanceScaling(float3 x,
|
||||
// Quality
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static std::tuple<TextureFormat, PixelDataFormat, PixelDataType> selectLutTextureParams(
|
||||
ColorGrading::LutFormat const lutFormat, const bool isOneDimensional) noexcept {
|
||||
if (isOneDimensional) {
|
||||
return { TextureFormat::R16F, PixelDataFormat::R, PixelDataType::HALF };
|
||||
}
|
||||
static std::tuple<TextureFormat, PixelDataFormat, PixelDataType>
|
||||
selectLutTextureParams(ColorGrading::LutFormat const lutFormat) noexcept {
|
||||
// We use RGBA16F for high quality modes instead of RGB16F because RGB16F
|
||||
// is not supported everywhere
|
||||
switch (lutFormat) {
|
||||
@@ -660,44 +658,27 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
|
||||
size_t lutElementCount = width * height * depth;
|
||||
size_t elementSize = mIsOneDimensional ? sizeof(half) : sizeof(half4);
|
||||
mDimension = c.lutDimension;
|
||||
|
||||
size_t lutElementCount = c.lutDimension * c.lutDimension * c.lutDimension;
|
||||
size_t elementSize = sizeof(half4);
|
||||
void* data = malloc(lutElementCount * elementSize);
|
||||
|
||||
auto [textureFormat, format, type] =
|
||||
selectLutTextureParams(builder->format, mIsOneDimensional);
|
||||
auto [textureFormat, format, type] = selectLutTextureParams(builder->format);
|
||||
assert_invariant(FTexture::isTextureFormatSupported(engine, textureFormat));
|
||||
assert_invariant(FTexture::validatePixelFormatAndType(textureFormat, format, type));
|
||||
|
||||
@@ -707,185 +688,170 @@ 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();
|
||||
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
} 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};
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should we do a runAndRetain() and defer the wait() + texture creation until
|
||||
// getHwHandle() is invoked?
|
||||
js.runAndWait(slices);
|
||||
});
|
||||
js.run(job);
|
||||
}
|
||||
|
||||
// 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,
|
||||
width, height, depth,
|
||||
c.lutDimension, c.lutDimension, c.lutDimension,
|
||||
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;
|
||||
|
||||
@@ -42,15 +42,12 @@ 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)
|
||||
|
||||
@@ -687,9 +687,6 @@ public:
|
||||
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
bool use_1d_lut = false;
|
||||
} color_grading;
|
||||
struct {
|
||||
bool use_shadow_atlas = false;
|
||||
} shadows;
|
||||
@@ -722,9 +719,6 @@ 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 },
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -52,10 +51,6 @@ IndexBuffer::Builder& IndexBuffer::Builder::name(const char* name, size_t const
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
IndexBuffer::Builder& IndexBuffer::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
IndexBuffer* IndexBuffer::Builder::build(Engine& engine) {
|
||||
return downcast(engine).createIndexBuffer(*this);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <math/mat3.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
@@ -56,10 +54,6 @@ InstanceBuffer::Builder& InstanceBuffer::Builder::name(const char* name, size_t
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
InstanceBuffer::Builder& InstanceBuffer::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
InstanceBuffer* InstanceBuffer::Builder::build(Engine& engine) {
|
||||
FILAMENT_CHECK_PRECONDITION(mImpl->mInstanceCount >= 1) << "instanceCount must be >= 1.";
|
||||
FILAMENT_CHECK_PRECONDITION(mImpl->mInstanceCount <= engine.getMaxAutomaticInstances())
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <math/norm.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -60,10 +59,6 @@ MorphTargetBuffer::Builder& MorphTargetBuffer::Builder::name(const char* name, s
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
MorphTargetBuffer::Builder& MorphTargetBuffer::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
MorphTargetBuffer* MorphTargetBuffer::Builder::build(Engine& engine) {
|
||||
return downcast(engine).createMorphTargetBuffer(*this);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <math/mat4.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
@@ -65,10 +64,6 @@ SkinningBuffer::Builder& SkinningBuffer::Builder::name(const char* name, size_t
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
SkinningBuffer::Builder& SkinningBuffer::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
SkinningBuffer* SkinningBuffer::Builder::build(Engine& engine) {
|
||||
return downcast(engine).createSkinningBuffer(*this);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <filament/Stream.h>
|
||||
|
||||
@@ -66,10 +65,6 @@ Stream::Builder& Stream::Builder::name(const char* name, size_t const len) noexc
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
Stream::Builder& Stream::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
Stream* Stream::Builder::build(Engine& engine) {
|
||||
return downcast(engine).createStream(*this);
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Panic.h>
|
||||
@@ -154,15 +152,10 @@ Texture::Builder& Texture::Builder::name(const char* name, size_t const len) noe
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
Texture::Builder& Texture::Builder::name(StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
Texture* Texture::Builder::build(Engine& engine) {
|
||||
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";
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/StaticString.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
@@ -153,10 +152,6 @@ VertexBuffer::Builder& VertexBuffer::Builder::name(const char* name, size_t cons
|
||||
return BuilderNameMixin::name(name, len);
|
||||
}
|
||||
|
||||
VertexBuffer::Builder& VertexBuffer::Builder::name(utils::StaticString const& name) noexcept {
|
||||
return BuilderNameMixin::name(name);
|
||||
}
|
||||
|
||||
VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
|
||||
FILAMENT_CHECK_PRECONDITION(mImpl->mVertexCount > 0) << "vertexCount cannot be 0";
|
||||
FILAMENT_CHECK_PRECONDITION(mImpl->mBufferCount > 0) << "bufferCount cannot be 0";
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
vec3 LogC_to_linear(const vec3 x) {
|
||||
vec3 colorGrade(mediump sampler3D lut, 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;
|
||||
return c * log2(a * x + b) + d;
|
||||
}
|
||||
vec3 logc = c * log2(a * x + b) + d;
|
||||
|
||||
vec3 colorGrade3D(mediump sampler3D lut, const vec3 v) {
|
||||
return textureLod(lut, v, 0.0).rgb;
|
||||
}
|
||||
// Remap to sample pixel centers
|
||||
logc = materialParams.lutSize.x + logc * materialParams.lutSize.y;
|
||||
|
||||
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);
|
||||
return textureLod(lut, logc, 0.0).rgb;
|
||||
}
|
||||
|
||||
@@ -66,16 +66,6 @@ material {
|
||||
precision : high
|
||||
}
|
||||
],
|
||||
constants : [
|
||||
{
|
||||
type : bool,
|
||||
name : isOneDimensional
|
||||
},
|
||||
{
|
||||
type : bool,
|
||||
name : isLDR
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
vertex
|
||||
],
|
||||
@@ -164,7 +154,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,16 +32,6 @@ material {
|
||||
name : vignetteColor
|
||||
}
|
||||
],
|
||||
constants : [
|
||||
{
|
||||
type : bool,
|
||||
name : isOneDimensional
|
||||
},
|
||||
{
|
||||
type : bool,
|
||||
name : isLDR
|
||||
}
|
||||
],
|
||||
subpasses : [
|
||||
{
|
||||
type : subpassInput,
|
||||
@@ -113,7 +103,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
|
||||
|
||||
@@ -10,11 +10,6 @@ material {
|
||||
type : float4,
|
||||
name : viewport,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : viewportInfo,
|
||||
precision: high
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
@@ -27,8 +22,8 @@ material {
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
postProcess.vertex.xy = materialParams.viewport.xy + postProcess.normalizedUV * materialParams.viewport.zw;
|
||||
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.vertex.xy);
|
||||
postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
|
||||
postProcess.vertex.xy = postProcess.normalizedUV;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +38,7 @@ fragment {
|
||||
#define gather textureGather
|
||||
#else
|
||||
vec4 gather(const mediump sampler2D color, highp vec2 p, const int comp) {
|
||||
highp ivec2 i = ivec2(p * materialParams.viewportInfo.zw - 0.5);
|
||||
highp ivec2 i = ivec2(p * materialParams.viewport.zw - 0.5);
|
||||
vec4 d;
|
||||
d[0] = texelFetchOffset(color, i, 0, ivec2(0, 1))[comp];
|
||||
d[1] = texelFetchOffset(color, i, 0, ivec2(1, 1))[comp];
|
||||
@@ -79,7 +74,7 @@ fragment {
|
||||
#include "sgsr1_shader_mobile.fs"
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
highp vec4 vp[1] = vec4[1]( materialParams.viewportInfo );
|
||||
highp vec4 vp[1] = vec4[1]( materialParams.viewport );
|
||||
postProcess.color = sgsr(materialParams_color, variable_vertex.xy, vp);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user