Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3308ec7e34 |
@@ -1,7 +1,15 @@
|
|||||||
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||||
;;; For more information see (info "(emacs) Directory Variables")
|
;;; For more information see (info "(emacs) Directory Variables")
|
||||||
|
|
||||||
((c++-mode . ((c-file-style . "filament")
|
((c++-mode . ((eval . (progn
|
||||||
|
(make-local-variable 'eglot-ignored-server-capabilities)
|
||||||
|
(add-to-list 'eglot-ignored-server-capabilities
|
||||||
|
:documentOnTypeFormattingProvider)))
|
||||||
|
(c-file-style . "filament")
|
||||||
(apheleia-inhibit . t)))
|
(apheleia-inhibit . t)))
|
||||||
(c-mode . ((c-file-style . "filament")
|
(c-mode . ((eval . (progn
|
||||||
|
(make-local-variable 'eglot-ignored-server-capabilities)
|
||||||
|
(add-to-list 'eglot-ignored-server-capabilities
|
||||||
|
:documentOnTypeFormattingProvider)))
|
||||||
|
(c-file-style . "filament")
|
||||||
(apheleia-inhibit . t))))
|
(apheleia-inhibit . t))))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ end_of_line = lf
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
|
|
||||||
[*.{c,cpp,h,inc,kt,java,js,md}]
|
[*.{c,cpp,h,inc,kt,java,js,md,fs,vs}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
max_line_length = 100
|
max_line_length = 100
|
||||||
|
|||||||
@@ -92,33 +92,26 @@ jobs:
|
|||||||
|
|
||||||
test-renderdiff:
|
test-renderdiff:
|
||||||
name: test-renderdiff
|
name: test-renderdiff
|
||||||
runs-on: macos-14-xlarge
|
runs-on: ubuntu-22.04-16core
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
- name: Set up Homebrew
|
- uses: ./.github/actions/ubuntu-apt-add-src
|
||||||
id: set-up-homebrew
|
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install python prereqs
|
|
||||||
run: pip install mako setuptools pyyaml
|
|
||||||
- name: Run script
|
- name: Run script
|
||||||
run: |
|
run: |
|
||||||
bash test/renderdiff/test.sh
|
source ./build/linux/ci-common.sh && bash test/renderdiff/test.sh
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: presubmit-renderdiff-result
|
name: presubmit-renderdiff-result
|
||||||
path: ./out/renderdiff_tests
|
path: ./out/renderdiff_tests
|
||||||
|
|
||||||
validate-wgsl-webgpu:
|
validate-wgsl-pipeline:
|
||||||
name: validate-wgsl-webgpu
|
name: validate-wgsl-pipeline
|
||||||
runs-on: ubuntu-22.04-8core
|
runs-on: macos-14-xlarge
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
run: ./build.sh -W debug test_filamat
|
||||||
- name: Run test
|
- name: Run test
|
||||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||||
@@ -139,14 +139,14 @@ else()
|
|||||||
set(LINUX FALSE)
|
set(LINUX FALSE)
|
||||||
endif()
|
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 (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)
|
if (FILAMENT_SUPPORTS_WAYLAND)
|
||||||
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
|
add_definitions(-DFILAMENT_SUPPORTS_WAYLAND)
|
||||||
set(FILAMENT_SUPPORTS_X11 FALSE)
|
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)
|
set(IS_HOST_PLATFORM TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
|
||||||
add_definitions(-DFILAMENT_SUPPORTS_OSMESA)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
||||||
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
||||||
@@ -607,14 +601,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# With WebGPU, push constants are not supported. Skinning uses them.
|
|
||||||
# WebGPU has a proposal to add push constants at https://github.com/gpuweb/gpuweb/blob/main/proposals/push-constants.md
|
|
||||||
# With WebGPU, Tint does not support ClipDistance which is used in Stereo. Mentioned in comment
|
|
||||||
# https://github.com/google/dawn/blob/855d17b08abdf02f9142bf5a8f14d0ea088810a4/src/tint/lang/spirv/reader/ast_parser/function.cc#L4434
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a webgpu --variant-filter=skinning,stereo)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Disable ESSL 1.0 code generation.
|
# Disable ESSL 1.0 code generation.
|
||||||
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||||
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
|
||||||
|
|||||||
@@ -7,6 +7,3 @@ for next branch cut* header.
|
|||||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||||
|
|
||||||
## Release notes for next branch cut
|
## Release notes for next branch cut
|
||||||
|
|
||||||
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.58.1'
|
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:
|
iOS projects can use CocoaPods to install the latest release:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pod 'Filament', '~> 1.58.1'
|
pod 'Filament', '~> 1.58.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -7,10 +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
|
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||||
|
|
||||||
## v1.58.2
|
|
||||||
|
|
||||||
- engine: Generate 1D instead of 3D LUTs for color grading whenever possible.
|
|
||||||
|
|
||||||
## v1.58.1
|
## v1.58.1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ buildscript {
|
|||||||
|
|
||||||
ext.versions = [
|
ext.versions = [
|
||||||
'jdk': 17,
|
'jdk': 17,
|
||||||
'minSdk': 26,
|
'minSdk': 21,
|
||||||
'targetSdk': 34,
|
'targetSdk': 34,
|
||||||
'compileSdk': 34,
|
'compileSdk': 34,
|
||||||
'kotlin': '2.0.21',
|
'kotlin': '2.0.21',
|
||||||
@@ -125,7 +125,7 @@ buildscript {
|
|||||||
ext.cmakeArgs = [
|
ext.cmakeArgs = [
|
||||||
"--no-warn-unused-cli",
|
"--no-warn-unused-cli",
|
||||||
"-DANDROID_PIE=ON",
|
"-DANDROID_PIE=ON",
|
||||||
"-DANDROID_PLATFORM=26",
|
"-DANDROID_PLATFORM=21",
|
||||||
"-DANDROID_STL=c++_static",
|
"-DANDROID_STL=c++_static",
|
||||||
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
||||||
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
||||||
@@ -200,7 +200,7 @@ subprojects {
|
|||||||
ndkVersion versions.ndk
|
ndkVersion versions.ndk
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 26
|
minSdkVersion versions.minSdk
|
||||||
targetSdkVersion versions.targetSdk
|
targetSdkVersion versions.targetSdk
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||||
# See third_party/dawn/tnt/CMakeLists.txt and libs/filamat/CMakeLists.txt
|
add_library(webgpu_dawn STATIC IMPORTED)
|
||||||
add_library(tint STATIC IMPORTED)
|
set_target_properties(webgpu_dawn PROPERTIES IMPORTED_LOCATION
|
||||||
set_target_properties(tint PROPERTIES IMPORTED_LOCATION
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebgpu_dawn.a)
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libtint_combined.a)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
||||||
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
||||||
@@ -57,5 +57,5 @@ target_link_libraries(filamat-jni
|
|||||||
utils
|
utils
|
||||||
log
|
log
|
||||||
smol-v
|
smol-v
|
||||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:tint>
|
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn> # for tint
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ add_library(filaflat STATIC IMPORTED)
|
|||||||
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
||||||
|
|
||||||
|
add_library(filamat STATIC IMPORTED)
|
||||||
|
set_target_properties(filamat PROPERTIES IMPORTED_LOCATION
|
||||||
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilamat.a)
|
||||||
|
|
||||||
add_library(geometry STATIC IMPORTED)
|
add_library(geometry STATIC IMPORTED)
|
||||||
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
||||||
@@ -55,11 +59,11 @@ add_library(smol-v STATIC IMPORTED)
|
|||||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||||
|
|
||||||
if (FILAMENT_ENABLE_FGVIEWER)
|
if (FILAMENT_ENABLE_FGVIEWER)
|
||||||
add_library(fgviewer STATIC IMPORTED)
|
add_library(fgviewer STATIC IMPORTED)
|
||||||
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_ENABLE_MATDBG)
|
if (FILAMENT_ENABLE_MATDBG)
|
||||||
add_library(matdbg STATIC IMPORTED)
|
add_library(matdbg STATIC IMPORTED)
|
||||||
|
|||||||
@@ -68,21 +68,6 @@ Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jcl
|
|||||||
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
|
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
|
||||||
Java_com_google_android_filament_Texture_nGetMaxTextureSize(JNIEnv *, jclass,
|
|
||||||
jlong nativeEngine, jint sampler) {
|
|
||||||
Engine *engine = (Engine *) nativeEngine;
|
|
||||||
return Texture::getMaxTextureSize(*engine, (Texture::Sampler)sampler);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
|
||||||
Java_com_google_android_filament_Texture_nGetMaxArrayTextureLayers(JNIEnv *, jclass,
|
|
||||||
jlong nativeEngine) {
|
|
||||||
Engine *engine = (Engine *) nativeEngine;
|
|
||||||
return Texture::getMaxArrayTextureLayers(*engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jboolean JNICALL
|
extern "C" JNIEXPORT jboolean JNICALL
|
||||||
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
|
Java_com_google_android_filament_Texture_nValidatePixelFormatAndType(JNIEnv*, jclass,
|
||||||
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
|
jint internalFormat, jint pixelDataFormat, jint pixelDataType) {
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ import static com.google.android.filament.Asserts.assertFloat4In;
|
|||||||
*
|
*
|
||||||
* <h1>Performance</h1>
|
* <h1>Performance</h1>
|
||||||
*
|
*
|
||||||
* Creating a new ColorGrading object may be more expensive than other Filament objects as a LUT may
|
* Creating a new ColorGrading object may be more expensive than other Filament objects as a
|
||||||
* need to be generated. The generation of this LUT, if necessary, may happen on the CPU.
|
* 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on
|
||||||
|
* the CPU.
|
||||||
*
|
*
|
||||||
* <h1>Ordering</h1>
|
* <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
|
* 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.
|
* 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}.
|
* The default quality is {@link QualityLevel#MEDIUM}.
|
||||||
*
|
*
|
||||||
* @param qualityLevel The desired quality of the color grading process
|
* @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
|
* 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().
|
* of the LUT. This overrides the value set by quality().
|
||||||
*
|
*
|
||||||
* This setting has no effect if generating a 1D LUT.
|
|
||||||
*
|
|
||||||
* The default is INTEGER
|
* The default is INTEGER
|
||||||
*
|
*
|
||||||
* @param format The desired format of the 3D LUT.
|
* @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.
|
* When color grading is implemented using a 3D LUT, this sets the dimension of the LUT.
|
||||||
* This overrides the value set by quality().
|
* This overrides the value set by quality().
|
||||||
*
|
*
|
||||||
* This setting has no effect if generating a 1D LUT.
|
|
||||||
*
|
|
||||||
* The default is 32
|
* The default is 32
|
||||||
*
|
*
|
||||||
* @param dim The desired dimension of the LUT. Between 16 and 64.
|
* @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);
|
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -691,24 +691,6 @@ public class Texture {
|
|||||||
pixelDataType.ordinal());
|
pixelDataType.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param engine {@link Engine}
|
|
||||||
* @param type Texture sampler type
|
|
||||||
* @return The maximum size in texels of a texture of type \p type. At least 2048 for
|
|
||||||
* 2D textures, 256 for 3D textures
|
|
||||||
*/
|
|
||||||
public static int getMaxTextureSize(@NonNull Engine engine, Sampler type) {
|
|
||||||
return nGetMaxTextureSize(engine.getNativeObject(), type.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param engine {@link Engine}
|
|
||||||
* @return The maximum number of layers supported by texture arrays. At least 256.
|
|
||||||
*/
|
|
||||||
public static int getMaxArrayTextureLayers(@NonNull Engine engine) {
|
|
||||||
return nGetMaxArrayTextureLayers(engine.getNativeObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
||||||
*/
|
*/
|
||||||
@@ -1307,8 +1289,6 @@ public class Texture {
|
|||||||
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
|
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
|
||||||
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
|
private static native boolean nIsTextureFormatMipmappable(long nativeEngine, int internalFormat);
|
||||||
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
|
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
|
||||||
private static native int nGetMaxTextureSize(long nativeObject, int ordinal);
|
|
||||||
private static native int nGetMaxArrayTextureLayers(long nativeObject);
|
|
||||||
|
|
||||||
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
|
private static native boolean nValidatePixelFormatAndType(int internalFormat, int pixelDataFormat,
|
||||||
int pixelDataType);
|
int pixelDataType);
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ package com.google.android.filament;
|
|||||||
* <li>DisplayRangeToneMapper</li>
|
* <li>DisplayRangeToneMapper</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* You can create custom tone mapping operators by subclassing ToneMapper.
|
||||||
*/
|
*/
|
||||||
public class ToneMapper {
|
public class ToneMapper {
|
||||||
private final long mNativeObject;
|
private final long mNativeObject;
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ project(filament-utils-android)
|
|||||||
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
||||||
set(IMAGEIO_DIR ../../libs/imageio)
|
set(IMAGEIO_DIR ../../libs/imageio)
|
||||||
|
|
||||||
set(CMAKE_SYSTEM_VERSION 26)
|
|
||||||
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../gltfio-android ${CMAKE_CURRENT_BINARY_DIR}/gltfio-android)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../gltfio-android ${CMAKE_CURRENT_BINARY_DIR}/gltfio-android)
|
||||||
|
|
||||||
add_library(camutils STATIC IMPORTED)
|
add_library(camutils STATIC IMPORTED)
|
||||||
@@ -32,10 +30,6 @@ add_library(iblprefilter STATIC IMPORTED)
|
|||||||
set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
|
set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
|
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
|
||||||
|
|
||||||
add_library(bluevk STATIC IMPORTED)
|
|
||||||
set_target_properties(bluevk PROPERTIES IMPORTED_LOCATION
|
|
||||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbluevk.a)
|
|
||||||
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
|
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||||
|
|
||||||
@@ -63,8 +57,7 @@ target_include_directories(filament-utils-jni PRIVATE
|
|||||||
..
|
..
|
||||||
../../filament/backend/include
|
../../filament/backend/include
|
||||||
${IMAGEIO_DIR}/include
|
${IMAGEIO_DIR}/include
|
||||||
../../libs/utils/include
|
../../libs/utils/include)
|
||||||
../../libs/bluevk/include)
|
|
||||||
|
|
||||||
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS
|
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.symbols)
|
${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.symbols)
|
||||||
@@ -78,6 +71,4 @@ target_link_libraries(filament-utils-jni
|
|||||||
image
|
image
|
||||||
ktxreader
|
ktxreader
|
||||||
viewer
|
viewer
|
||||||
bluevk
|
|
||||||
android
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion 26
|
|
||||||
}
|
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
// No need to package up the following shared libs, which arise as a side effect of our
|
// No need to package up the following shared libs, which arise as a side effect of our
|
||||||
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
||||||
|
|||||||
@@ -14,21 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <android/hardware_buffer.h>
|
|
||||||
#include <android/hardware_buffer_jni.h>
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
#include <filament/Engine.h>
|
#include <filament/Engine.h>
|
||||||
#include <filament/IndirectLight.h>
|
#include <filament/IndirectLight.h>
|
||||||
#include <filament/Skybox.h>
|
#include <filament/Skybox.h>
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
|
||||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
|
||||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
|
||||||
|
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
#include <ktxreader/Ktx1Reader.h>
|
#include <ktxreader/Ktx1Reader.h>
|
||||||
|
|
||||||
#include "common/NioUtils.h"
|
#include "common/NioUtils.h"
|
||||||
@@ -38,8 +29,6 @@ using namespace filament::math;
|
|||||||
using namespace image;
|
using namespace image;
|
||||||
using namespace ktxreader;
|
using namespace ktxreader;
|
||||||
|
|
||||||
using namespace filament::backend;
|
|
||||||
|
|
||||||
jlong nCreateHDRTexture(JNIEnv* env, jclass,
|
jlong nCreateHDRTexture(JNIEnv* env, jclass,
|
||||||
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat);
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat);
|
||||||
|
|
||||||
@@ -90,37 +79,6 @@ static jboolean nGetSphericalHarmonics(JNIEnv* env, jclass, jobject javaBuffer,
|
|||||||
return success ? JNI_TRUE : JNI_FALSE;
|
return success ? JNI_TRUE : JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jlong nSetExternalImageOnTexture(JNIEnv* env, jclass, jlong nativeEngine, jlong nativeTexture,
|
|
||||||
jobject hardwareBuffer, jboolean srgb) {
|
|
||||||
utils::slog.e <<"--------- jni nSetExternalImageOnTexture" << utils::io::endl;
|
|
||||||
Engine* engine = (Engine*) nativeEngine;
|
|
||||||
Texture* texture = (Texture*) nativeTexture;
|
|
||||||
|
|
||||||
Platform* platform = engine->getPlatform();
|
|
||||||
AHardwareBuffer* nativeBuffer = nullptr;
|
|
||||||
if (__builtin_available(android 26, *)) {
|
|
||||||
nativeBuffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::slog.e <<"--------- jni nSetExternalImageOnTexture buf=" << nativeBuffer << utils::io::endl;
|
|
||||||
|
|
||||||
if (!nativeBuffer) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine->getBackend() == Backend::OPENGL) {
|
|
||||||
PlatformEGLAndroid* eglPlatform = (PlatformEGLAndroid*) platform;
|
|
||||||
auto ref = eglPlatform->createExternalImage(nativeBuffer, srgb == JNI_TRUE);
|
|
||||||
texture->setExternalImage(*engine, ref);
|
|
||||||
} else if (engine->getBackend() == Backend::VULKAN) {
|
|
||||||
VulkanPlatformAndroid* vulkanPlatform = (VulkanPlatformAndroid*) platform;
|
|
||||||
auto ref = vulkanPlatform->createExternalImage(nativeBuffer, srgb == JNI_TRUE);
|
|
||||||
texture->setExternalImage(*engine, ref);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
||||||
JNIEnv* env;
|
JNIEnv* env;
|
||||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||||
@@ -150,14 +108,5 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
|||||||
rc = env->RegisterNatives(hdrloaderClass, hdrMethods, sizeof(hdrMethods) / sizeof(JNINativeMethod));
|
rc = env->RegisterNatives(hdrloaderClass, hdrMethods, sizeof(hdrMethods) / sizeof(JNINativeMethod));
|
||||||
if (rc != JNI_OK) return rc;
|
if (rc != JNI_OK) return rc;
|
||||||
|
|
||||||
jclass loaderClass = env->FindClass("com/google/android/filament/utils/ExternalImage");
|
|
||||||
if (loaderClass == nullptr) return JNI_ERR;
|
|
||||||
static const JNINativeMethod methods[] = {
|
|
||||||
{ (char*) "nSetExternalImageOnTexture", (char*) "(JJLandroid/hardware/HardwareBuffer;Z)J",
|
|
||||||
reinterpret_cast<void*>(nSetExternalImageOnTexture) },
|
|
||||||
};
|
|
||||||
rc = env->RegisterNatives(loaderClass, methods, sizeof(methods) / sizeof(JNINativeMethod));
|
|
||||||
if (rc != JNI_OK) return rc;
|
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Romain Guy
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.android.filament.utils
|
|
||||||
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import com.google.android.filament.Engine
|
|
||||||
import com.google.android.filament.Texture
|
|
||||||
|
|
||||||
object ExternalImage {
|
|
||||||
fun setOnTexture(
|
|
||||||
engine: Engine,
|
|
||||||
texture: Texture,
|
|
||||||
buffer: HardwareBuffer,
|
|
||||||
srgb: Boolean,
|
|
||||||
) {
|
|
||||||
val nativeEngine = engine.nativeObject
|
|
||||||
val nativeTexture = texture.nativeObject
|
|
||||||
val l = nSetExternalImageOnTexture(nativeEngine, nativeTexture, buffer, srgb)
|
|
||||||
}
|
|
||||||
|
|
||||||
private external fun nSetExternalImageOnTexture(
|
|
||||||
nativeEngine: Long,
|
|
||||||
nativeTexture: Long,
|
|
||||||
buffer: HardwareBuffer,
|
|
||||||
srgb: Boolean,
|
|
||||||
): Long
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.58.1
|
VERSION_NAME=1.58.0
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
*.iml
|
|
||||||
.gradle
|
|
||||||
/local.properties
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/libraries
|
|
||||||
/.idea/caches
|
|
||||||
/.idea/gradle.xml
|
|
||||||
.DS_Store
|
|
||||||
/build
|
|
||||||
/captures
|
|
||||||
/src/main/assets
|
|
||||||
.externalNativeBuild
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'com.android.application'
|
|
||||||
id 'kotlin-android'
|
|
||||||
id 'filament-tools-plugin'
|
|
||||||
}
|
|
||||||
|
|
||||||
project.ext.isSample = true
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain(versions.jdk)
|
|
||||||
}
|
|
||||||
|
|
||||||
filamentTools {
|
|
||||||
materialInputDir = project.layout.projectDirectory.dir("src/main/materials")
|
|
||||||
materialOutputDir = project.layout.projectDirectory.dir("src/main/assets/materials")
|
|
||||||
}
|
|
||||||
|
|
||||||
clean.doFirst {
|
|
||||||
delete "src/main/assets"
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace 'com.google.android.filament.externalimg'
|
|
||||||
|
|
||||||
compileSdkVersion versions.compileSdk
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "com.google.android.filament.externalimg"
|
|
||||||
minSdkVersion 26
|
|
||||||
targetSdkVersion versions.targetSdk
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
|
||||||
// is not configuration-cache friendly yet; this is only useful for Play publication
|
|
||||||
dependenciesInfo {
|
|
||||||
includeInApk = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use the .filamat extension for materials compiled with matc
|
|
||||||
// Telling aapt to not compress them allows to load them efficiently
|
|
||||||
aaptOptions {
|
|
||||||
noCompress 'filamat', 'ktx'
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility versions.jdk
|
|
||||||
targetCompatibility versions.jdk
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation deps.kotlin
|
|
||||||
implementation deps.androidx.core
|
|
||||||
implementation project(':filament-android')
|
|
||||||
implementation project(':filament-utils-android')
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2019 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
|
||||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
<activity
|
|
||||||
android:exported="true"
|
|
||||||
android:name=".MainActivity">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.android.filament.externalimg
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.graphics.SurfaceTexture
|
|
||||||
import android.hardware.camera2.*
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.util.Log
|
|
||||||
import android.util.Size
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.graphics.ImageFormat
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.media.ImageReader
|
|
||||||
import android.opengl.Matrix
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Looper
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
|
|
||||||
import com.google.android.filament.*
|
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toy class that handles all interaction with the Android camera2 API.
|
|
||||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
|
||||||
*/
|
|
||||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance) {
|
|
||||||
private lateinit var cameraId: String
|
|
||||||
private lateinit var captureRequest: CaptureRequest
|
|
||||||
|
|
||||||
private val cameraOpenCloseLock = Semaphore(1)
|
|
||||||
private var backgroundHandler: Handler? = null
|
|
||||||
private var backgroundThread: HandlerThread? = null
|
|
||||||
private var cameraDevice: CameraDevice? = null
|
|
||||||
private var captureSession: CameraCaptureSession? = null
|
|
||||||
private var resolution = Size(640, 480)
|
|
||||||
private var filamentTexture: Texture? = null
|
|
||||||
private var filamentStream: Stream? = null
|
|
||||||
private val imageReader = ImageReader.newInstance(
|
|
||||||
resolution.width,
|
|
||||||
resolution.height,
|
|
||||||
ImageFormat.PRIVATE,
|
|
||||||
kImageReaderMaxImages,
|
|
||||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
|
|
||||||
|
|
||||||
@Suppress("deprecation")
|
|
||||||
private val display = if (Build.VERSION.SDK_INT >= 30) {
|
|
||||||
Api30Impl.getDisplay(activity)
|
|
||||||
} else {
|
|
||||||
activity.windowManager.defaultDisplay!!
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(30)
|
|
||||||
class Api30Impl {
|
|
||||||
companion object {
|
|
||||||
fun getDisplay(context: Context) = context.display!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
|
||||||
override fun onOpened(cameraDevice: CameraDevice) {
|
|
||||||
cameraOpenCloseLock.release()
|
|
||||||
this@CameraHelper.cameraDevice = cameraDevice
|
|
||||||
createCaptureSession()
|
|
||||||
}
|
|
||||||
override fun onDisconnected(cameraDevice: CameraDevice) {
|
|
||||||
cameraOpenCloseLock.release()
|
|
||||||
cameraDevice.close()
|
|
||||||
this@CameraHelper.cameraDevice = null
|
|
||||||
}
|
|
||||||
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
|
||||||
onDisconnected(cameraDevice)
|
|
||||||
this@CameraHelper.activity.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the latest image (if any) from ImageReader and passes its HardwareBuffer to Filament.
|
|
||||||
*/
|
|
||||||
fun pushExternalImageToFilament() {
|
|
||||||
val stream = filamentStream
|
|
||||||
if (stream != null) {
|
|
||||||
imageReader.acquireLatestImage()?.also {
|
|
||||||
stream.setAcquiredImage(it.hardwareBuffer, Handler(Looper.getMainLooper())) {
|
|
||||||
it.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the front-facing Android camera, requests permission, and sets up a listener that will
|
|
||||||
* start a capture session as soon as the camera is ready.
|
|
||||||
*/
|
|
||||||
fun openCamera() {
|
|
||||||
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
|
||||||
try {
|
|
||||||
for (cameraId in manager.cameraIdList) {
|
|
||||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
|
||||||
val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
|
|
||||||
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cameraId = cameraId
|
|
||||||
Log.i(kLogTag, "Selected camera $cameraId.")
|
|
||||||
|
|
||||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
|
|
||||||
resolution = map.getOutputSizes(SurfaceTexture::class.java)[0]
|
|
||||||
Log.i(kLogTag, "Highest resolution is $resolution.")
|
|
||||||
}
|
|
||||||
} catch (e: CameraAccessException) {
|
|
||||||
Log.e(kLogTag, e.toString())
|
|
||||||
} catch (e: NullPointerException) {
|
|
||||||
Log.e(kLogTag, "Camera2 API is not supported on this device.")
|
|
||||||
}
|
|
||||||
|
|
||||||
val permission = ContextCompat.checkSelfPermission(this.activity, Manifest.permission.CAMERA)
|
|
||||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), kRequestCameraPermission)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
|
||||||
throw RuntimeException("Time out waiting to lock camera opening.")
|
|
||||||
}
|
|
||||||
manager.openCamera(cameraId, cameraCallback, backgroundHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onResume() {
|
|
||||||
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
|
|
||||||
backgroundHandler = Handler(backgroundThread?.looper!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPause() {
|
|
||||||
backgroundThread?.quitSafely()
|
|
||||||
try {
|
|
||||||
backgroundThread?.join()
|
|
||||||
backgroundThread = null
|
|
||||||
backgroundHandler = null
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
Log.e(kLogTag, e.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
|
||||||
if (requestCode == kRequestCameraPermission) {
|
|
||||||
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
Log.e(kLogTag, "Unable to obtain camera position.")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCaptureSession() {
|
|
||||||
filamentStream?.apply { filamentEngine.destroyStream(this) }
|
|
||||||
|
|
||||||
// [Re]create the Filament Stream object that gets bound to the Texture.
|
|
||||||
filamentStream = Stream.Builder().build(filamentEngine)
|
|
||||||
|
|
||||||
// Create the Filament Texture object if we haven't done so already.
|
|
||||||
if (filamentTexture == null) {
|
|
||||||
filamentTexture = Texture.Builder()
|
|
||||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
|
||||||
.format(Texture.InternalFormat.RGB8)
|
|
||||||
.build(filamentEngine)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
|
||||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
|
||||||
val aspectRatio = resolution.width.toFloat() / resolution.height.toFloat()
|
|
||||||
val textureTransform = FloatArray(16)
|
|
||||||
Matrix.setIdentityM(textureTransform, 0)
|
|
||||||
when (display.rotation) {
|
|
||||||
Surface.ROTATION_0 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.rotateM(textureTransform, 0, 90.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f, 1.0f / aspectRatio, 1.0f)
|
|
||||||
}
|
|
||||||
Surface.ROTATION_90 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 1.0f, 0.0f)
|
|
||||||
Matrix.rotateM(textureTransform, 0, 180.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
|
||||||
}
|
|
||||||
Surface.ROTATION_270 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
|
||||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
|
||||||
filamentTexture!!.setExternalStream(filamentEngine, filamentStream!!)
|
|
||||||
filamentMaterial.setParameter("videoTexture", filamentTexture!!, sampler)
|
|
||||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
|
||||||
|
|
||||||
// Start the capture session. You could also use TEMPLATE_PREVIEW here.
|
|
||||||
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
|
|
||||||
captureRequestBuilder.addTarget(imageReader.surface)
|
|
||||||
|
|
||||||
cameraDevice?.createCaptureSession(listOf(imageReader.surface),
|
|
||||||
object : CameraCaptureSession.StateCallback() {
|
|
||||||
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
|
|
||||||
if (cameraDevice == null) return
|
|
||||||
captureSession = cameraCaptureSession
|
|
||||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
|
||||||
captureRequest = captureRequestBuilder.build()
|
|
||||||
captureSession!!.setRepeatingRequest(captureRequest, null, backgroundHandler)
|
|
||||||
Log.i(kLogTag, "Created CaptureRequest.")
|
|
||||||
}
|
|
||||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
|
||||||
Log.e(kLogTag, "onConfigureFailed")
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val kLogTag = "CameraHelper"
|
|
||||||
private const val kRequestCameraPermission = 1
|
|
||||||
private const val kImageReaderMaxImages = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.android.filament.externalimg
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.graphics.SurfaceTexture
|
|
||||||
import android.hardware.camera2.*
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.util.Log
|
|
||||||
import android.util.Size
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.graphics.ImageFormat
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.media.ImageReader
|
|
||||||
import android.opengl.Matrix
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Looper
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
|
|
||||||
import com.google.android.filament.*
|
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toy class that handles all interaction with the Android camera2 API.
|
|
||||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
|
||||||
*/
|
|
||||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance) {
|
|
||||||
private lateinit var cameraId: String
|
|
||||||
private lateinit var captureRequest: CaptureRequest
|
|
||||||
|
|
||||||
private val cameraOpenCloseLock = Semaphore(1)
|
|
||||||
private var backgroundHandler: Handler? = null
|
|
||||||
private var backgroundThread: HandlerThread? = null
|
|
||||||
private var cameraDevice: CameraDevice? = null
|
|
||||||
private var captureSession: CameraCaptureSession? = null
|
|
||||||
private var resolution = Size(640, 480)
|
|
||||||
private var filamentTexture: Texture? = null
|
|
||||||
private var filamentStream: Stream? = null
|
|
||||||
private val imageReader = ImageReader.newInstance(
|
|
||||||
resolution.width,
|
|
||||||
resolution.height,
|
|
||||||
ImageFormat.PRIVATE,
|
|
||||||
kImageReaderMaxImages,
|
|
||||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
|
|
||||||
|
|
||||||
@Suppress("deprecation")
|
|
||||||
private val display = if (Build.VERSION.SDK_INT >= 30) {
|
|
||||||
Api30Impl.getDisplay(activity)
|
|
||||||
} else {
|
|
||||||
activity.windowManager.defaultDisplay!!
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(30)
|
|
||||||
class Api30Impl {
|
|
||||||
companion object {
|
|
||||||
fun getDisplay(context: Context) = context.display!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
|
||||||
override fun onOpened(cameraDevice: CameraDevice) {
|
|
||||||
cameraOpenCloseLock.release()
|
|
||||||
this@CameraHelper.cameraDevice = cameraDevice
|
|
||||||
createCaptureSession()
|
|
||||||
}
|
|
||||||
override fun onDisconnected(cameraDevice: CameraDevice) {
|
|
||||||
cameraOpenCloseLock.release()
|
|
||||||
cameraDevice.close()
|
|
||||||
this@CameraHelper.cameraDevice = null
|
|
||||||
}
|
|
||||||
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
|
||||||
onDisconnected(cameraDevice)
|
|
||||||
this@CameraHelper.activity.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the latest image (if any) from ImageReader and passes its HardwareBuffer to Filament.
|
|
||||||
*/
|
|
||||||
fun pushExternalImageToFilament() {
|
|
||||||
val stream = filamentStream
|
|
||||||
if (stream != null) {
|
|
||||||
imageReader.acquireLatestImage()?.also {
|
|
||||||
stream.setAcquiredImage(it.hardwareBuffer, Handler(Looper.getMainLooper())) {
|
|
||||||
it.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the front-facing Android camera, requests permission, and sets up a listener that will
|
|
||||||
* start a capture session as soon as the camera is ready.
|
|
||||||
*/
|
|
||||||
fun openCamera() {
|
|
||||||
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
|
||||||
try {
|
|
||||||
for (cameraId in manager.cameraIdList) {
|
|
||||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
|
||||||
val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
|
|
||||||
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cameraId = cameraId
|
|
||||||
Log.i(kLogTag, "Selected camera $cameraId.")
|
|
||||||
|
|
||||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
|
|
||||||
resolution = map.getOutputSizes(SurfaceTexture::class.java)[0]
|
|
||||||
Log.i(kLogTag, "Highest resolution is $resolution.")
|
|
||||||
}
|
|
||||||
} catch (e: CameraAccessException) {
|
|
||||||
Log.e(kLogTag, e.toString())
|
|
||||||
} catch (e: NullPointerException) {
|
|
||||||
Log.e(kLogTag, "Camera2 API is not supported on this device.")
|
|
||||||
}
|
|
||||||
|
|
||||||
val permission = ContextCompat.checkSelfPermission(this.activity, Manifest.permission.CAMERA)
|
|
||||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), kRequestCameraPermission)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
|
||||||
throw RuntimeException("Time out waiting to lock camera opening.")
|
|
||||||
}
|
|
||||||
manager.openCamera(cameraId, cameraCallback, backgroundHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onResume() {
|
|
||||||
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
|
|
||||||
backgroundHandler = Handler(backgroundThread?.looper!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPause() {
|
|
||||||
backgroundThread?.quitSafely()
|
|
||||||
try {
|
|
||||||
backgroundThread?.join()
|
|
||||||
backgroundThread = null
|
|
||||||
backgroundHandler = null
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
Log.e(kLogTag, e.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
|
||||||
if (requestCode == kRequestCameraPermission) {
|
|
||||||
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
Log.e(kLogTag, "Unable to obtain camera position.")
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCaptureSession() {
|
|
||||||
filamentStream?.apply { filamentEngine.destroyStream(this) }
|
|
||||||
|
|
||||||
// [Re]create the Filament Stream object that gets bound to the Texture.
|
|
||||||
filamentStream = Stream.Builder().build(filamentEngine)
|
|
||||||
|
|
||||||
// Create the Filament Texture object if we haven't done so already.
|
|
||||||
if (filamentTexture == null) {
|
|
||||||
filamentTexture = Texture.Builder()
|
|
||||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
|
||||||
.format(Texture.InternalFormat.RGB8)
|
|
||||||
.build(filamentEngine)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
|
||||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
|
||||||
val aspectRatio = resolution.width.toFloat() / resolution.height.toFloat()
|
|
||||||
val textureTransform = FloatArray(16)
|
|
||||||
Matrix.setIdentityM(textureTransform, 0)
|
|
||||||
when (display.rotation) {
|
|
||||||
Surface.ROTATION_0 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.rotateM(textureTransform, 0, 90.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f, 1.0f / aspectRatio, 1.0f)
|
|
||||||
}
|
|
||||||
Surface.ROTATION_90 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 1.0f, 0.0f)
|
|
||||||
Matrix.rotateM(textureTransform, 0, 180.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
|
||||||
}
|
|
||||||
Surface.ROTATION_270 -> {
|
|
||||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
|
||||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
|
||||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
|
||||||
filamentTexture!!.setExternalStream(filamentEngine, filamentStream!!)
|
|
||||||
filamentMaterial.setParameter("videoTexture", filamentTexture!!, sampler)
|
|
||||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
|
||||||
|
|
||||||
// Start the capture session. You could also use TEMPLATE_PREVIEW here.
|
|
||||||
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
|
|
||||||
captureRequestBuilder.addTarget(imageReader.surface)
|
|
||||||
|
|
||||||
cameraDevice?.createCaptureSession(listOf(imageReader.surface),
|
|
||||||
object : CameraCaptureSession.StateCallback() {
|
|
||||||
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
|
|
||||||
if (cameraDevice == null) return
|
|
||||||
captureSession = cameraCaptureSession
|
|
||||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
|
||||||
captureRequest = captureRequestBuilder.build()
|
|
||||||
captureSession!!.setRepeatingRequest(captureRequest, null, backgroundHandler)
|
|
||||||
Log.i(kLogTag, "Created CaptureRequest.")
|
|
||||||
}
|
|
||||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
|
||||||
Log.e(kLogTag, "onConfigureFailed")
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val kLogTag = "CameraHelper"
|
|
||||||
private const val kRequestCameraPermission = 1
|
|
||||||
private const val kImageReaderMaxImages = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
import android.graphics.*
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.media.Image
|
|
||||||
import android.media.ImageReader
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import java.util.concurrent.CompletableFuture
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
object CanvasToHardwareBufferUtil {
|
|
||||||
private const val TAG = "CanvasToHardwareBufferKt"
|
|
||||||
private const val IMAGE_READER_TIMEOUT_MS = 3000L // Timeout for waiting buffer
|
|
||||||
|
|
||||||
fun drawToHardwareBuffer(
|
|
||||||
width: Int,
|
|
||||||
height: Int,
|
|
||||||
): HardwareBuffer? {
|
|
||||||
if (width <= 0 || height <= 0) {
|
|
||||||
Log.e(TAG, "Invalid dimensions: width=$width, height=$height")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
var handlerThread: HandlerThread? = null
|
|
||||||
var imageReader: ImageReader? = null
|
|
||||||
var surface: Surface? = null // Keep track for logging/debugging if needed
|
|
||||||
// Use var as it's assigned within the try block after future completion
|
|
||||||
var receivedHardwareBuffer: HardwareBuffer? = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 1. Setup HandlerThread for ImageReader callbacks
|
|
||||||
handlerThread = HandlerThread("ImageReaderThreadKt").apply { start() }
|
|
||||||
val imageReaderHandler = Handler(handlerThread.looper)
|
|
||||||
|
|
||||||
// 2. Use CompletableFuture to wait for the buffer from the listener
|
|
||||||
val bufferFuture = CompletableFuture<HardwareBuffer>()
|
|
||||||
|
|
||||||
// 3. Create ImageReader
|
|
||||||
val usageFlags =
|
|
||||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
|
|
||||||
HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
|
|
||||||
HardwareBuffer.USAGE_CPU_READ_RARELY // Adjust as needed
|
|
||||||
|
|
||||||
imageReader =
|
|
||||||
ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1, usageFlags)
|
|
||||||
|
|
||||||
// 4. Set Listener to capture the buffer
|
|
||||||
imageReader.setOnImageAvailableListener({ reader ->
|
|
||||||
var image: Image? = null
|
|
||||||
var hardwareBuffer: HardwareBuffer? = null
|
|
||||||
try {
|
|
||||||
// Use `use` block for automatic image.close()
|
|
||||||
image = reader.acquireLatestImage()
|
|
||||||
if (image == null) {
|
|
||||||
Log.w(TAG, "ImageReader listener fired but no image available.")
|
|
||||||
// Complete exceptionally if buffer wasn't already completed.
|
|
||||||
bufferFuture.completeExceptionally(
|
|
||||||
RuntimeException("ImageReader listener fired but no image available"),
|
|
||||||
)
|
|
||||||
return@setOnImageAvailableListener
|
|
||||||
}
|
|
||||||
|
|
||||||
hardwareBuffer = image.hardwareBuffer
|
|
||||||
if (hardwareBuffer != null) {
|
|
||||||
// IMPORTANT: Don't close the HardwareBuffer here!
|
|
||||||
// Transfer ownership via the CompletableFuture.
|
|
||||||
if (!bufferFuture.isDone) { // Avoid completing more than once
|
|
||||||
bufferFuture.complete(hardwareBuffer)
|
|
||||||
} else {
|
|
||||||
// Future was already completed (maybe exceptionally), close this buffer
|
|
||||||
Log.w(TAG, "Future already done, closing redundant HardwareBuffer")
|
|
||||||
hardwareBuffer.close()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Failed to get HardwareBuffer from Image.")
|
|
||||||
if (!bufferFuture.isDone) {
|
|
||||||
bufferFuture.completeExceptionally(
|
|
||||||
RuntimeException("Failed to get HardwareBuffer from Image"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error in ImageReader listener", e)
|
|
||||||
if (!bufferFuture.isDone) {
|
|
||||||
bufferFuture.completeExceptionally(e) // Propagate error
|
|
||||||
}
|
|
||||||
// If we got the buffer but failed elsewhere, ensure it's closed
|
|
||||||
hardwareBuffer?.takeUnless { it.isClosed }?.close()
|
|
||||||
} finally {
|
|
||||||
// image?.close() // Handled by acquiring reader itself or image.use{} if used
|
|
||||||
image?.close() // Close image if not using `use` or if error before `use` finishes
|
|
||||||
}
|
|
||||||
}, imageReaderHandler)
|
|
||||||
|
|
||||||
// 5. Get the Surface to draw onto
|
|
||||||
surface =
|
|
||||||
imageReader.surface
|
|
||||||
?: throw RuntimeException("Failed to get Surface from ImageReader")
|
|
||||||
|
|
||||||
// 6. Lock Canvas and Draw
|
|
||||||
val canvas: Canvas? = surface.lockHardwareCanvas() // Use hardware accelerated canvas
|
|
||||||
if (canvas != null) {
|
|
||||||
try {
|
|
||||||
// --- Your Drawing Code Here ---
|
|
||||||
val paint =
|
|
||||||
Paint().apply {
|
|
||||||
isAntiAlias = true // Good practice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blue background
|
|
||||||
paint.color = Color.BLUE
|
|
||||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
|
|
||||||
|
|
||||||
// White text
|
|
||||||
paint.color = Color.WHITE
|
|
||||||
paint.textSize = 40f
|
|
||||||
paint.textAlign = Paint.Align.CENTER
|
|
||||||
canvas.drawText(
|
|
||||||
"Hello HardwareBuffer! (Kotlin)",
|
|
||||||
width / 2f,
|
|
||||||
height / 2f,
|
|
||||||
paint,
|
|
||||||
)
|
|
||||||
// --- End Drawing Code ---
|
|
||||||
} finally {
|
|
||||||
// 7. Unlock Canvas and Post
|
|
||||||
surface.unlockCanvasAndPost(canvas)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw RuntimeException("Failed to lock Hardware Canvas")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. Wait for the listener to provide the HardwareBuffer
|
|
||||||
try {
|
|
||||||
// Wait for the buffer; this blocks the current thread.
|
|
||||||
receivedHardwareBuffer =
|
|
||||||
bufferFuture.get(IMAGE_READER_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
|
||||||
// Ownership of receivedHardwareBuffer is now transferred to the caller
|
|
||||||
} catch (timeout: TimeoutException) {
|
|
||||||
Log.e(TAG, "Timeout waiting for HardwareBuffer from ImageReader listener")
|
|
||||||
bufferFuture.cancel(true) // Attempt to cancel listener processing
|
|
||||||
throw timeout // Re-throw
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Failed to draw to HardwareBuffer", e)
|
|
||||||
// Ensure buffer is closed if acquired but an error occurred before returning it
|
|
||||||
receivedHardwareBuffer?.takeUnless { it.isClosed }?.close()
|
|
||||||
return null // Indicate failure
|
|
||||||
} finally {
|
|
||||||
// 9. Cleanup
|
|
||||||
try {
|
|
||||||
imageReader?.close() // Also releases the Surface implicitly
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error closing ImageReader", e)
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
handlerThread?.quitSafely()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error quitting HandlerThread", e)
|
|
||||||
}
|
|
||||||
// Note: Do NOT close receivedHardwareBuffer here if returning successfully.
|
|
||||||
// The caller is responsible for closing the returned buffer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the buffer; caller MUST close it.
|
|
||||||
return receivedHardwareBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Example Usage (must be called from appropriate context/thread, like a coroutine) ---
|
|
||||||
/*
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
suspend fun exampleUsage() = withContext(Dispatchers.IO) { // Run blocking code off main thread
|
|
||||||
val myBuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(640, 480)
|
|
||||||
|
|
||||||
// Use the 'use' extension function for automatic closing
|
|
||||||
myBuffer?.use { buffer ->
|
|
||||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
|
||||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
|
||||||
// buffer.close() // 'use' handles this automatically
|
|
||||||
|
|
||||||
} ?: run {
|
|
||||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG,"HardwareBuffer processing finished (buffer closed if obtained).")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
import android.graphics.*
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.media.Image
|
|
||||||
import android.media.ImageReader
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import java.util.concurrent.CompletableFuture
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
object CanvasToHardwareBufferUtil {
|
|
||||||
|
|
||||||
private const val TAG = "CanvasToHardwareBufferKt"
|
|
||||||
private const val IMAGE_READER_TIMEOUT_MS = 3000L // Timeout for waiting buffer
|
|
||||||
|
|
||||||
fun drawToHardwareBuffer(width: Int, height: Int): HardwareBuffer? {
|
|
||||||
if (width <= 0 || height <= 0) {
|
|
||||||
Log.e(TAG, "Invalid dimensions: width=$width, height=$height")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
var handlerThread: HandlerThread? = null
|
|
||||||
var imageReader: ImageReader? = null
|
|
||||||
var surface: Surface? = null // Keep track for logging/debugging if needed
|
|
||||||
// Use var as it's assigned within the try block after future completion
|
|
||||||
var receivedHardwareBuffer: HardwareBuffer? = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 1. Setup HandlerThread for ImageReader callbacks
|
|
||||||
handlerThread = HandlerThread("ImageReaderThreadKt").apply { start() }
|
|
||||||
val imageReaderHandler = Handler(handlerThread.looper)
|
|
||||||
|
|
||||||
// 2. Use CompletableFuture to wait for the buffer from the listener
|
|
||||||
val bufferFuture = CompletableFuture<HardwareBuffer>()
|
|
||||||
|
|
||||||
// 3. Create ImageReader
|
|
||||||
val usageFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
|
|
||||||
HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
|
|
||||||
HardwareBuffer.USAGE_CPU_READ_RARELY // Adjust as needed
|
|
||||||
|
|
||||||
imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1, usageFlags)
|
|
||||||
|
|
||||||
// 4. Set Listener to capture the buffer
|
|
||||||
imageReader.setOnImageAvailableListener({ reader ->
|
|
||||||
var image: Image? = null
|
|
||||||
var hardwareBuffer: HardwareBuffer? = null
|
|
||||||
try {
|
|
||||||
// Use `use` block for automatic image.close()
|
|
||||||
image = reader.acquireLatestImage()
|
|
||||||
if (image == null) {
|
|
||||||
Log.w(TAG, "ImageReader listener fired but no image available.")
|
|
||||||
// Complete exceptionally if buffer wasn't already completed.
|
|
||||||
bufferFuture.completeExceptionally(RuntimeException("ImageReader listener fired but no image available"))
|
|
||||||
return@setOnImageAvailableListener
|
|
||||||
}
|
|
||||||
|
|
||||||
hardwareBuffer = image.hardwareBuffer
|
|
||||||
if (hardwareBuffer != null) {
|
|
||||||
// IMPORTANT: Don't close the HardwareBuffer here!
|
|
||||||
// Transfer ownership via the CompletableFuture.
|
|
||||||
if (!bufferFuture.isDone) { // Avoid completing more than once
|
|
||||||
bufferFuture.complete(hardwareBuffer)
|
|
||||||
} else {
|
|
||||||
// Future was already completed (maybe exceptionally), close this buffer
|
|
||||||
Log.w(TAG, "Future already done, closing redundant HardwareBuffer")
|
|
||||||
hardwareBuffer.close()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Failed to get HardwareBuffer from Image.")
|
|
||||||
if (!bufferFuture.isDone) {
|
|
||||||
bufferFuture.completeExceptionally(RuntimeException("Failed to get HardwareBuffer from Image"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error in ImageReader listener", e)
|
|
||||||
if (!bufferFuture.isDone) {
|
|
||||||
bufferFuture.completeExceptionally(e) // Propagate error
|
|
||||||
}
|
|
||||||
// If we got the buffer but failed elsewhere, ensure it's closed
|
|
||||||
hardwareBuffer?.takeUnless { it.isClosed }?.close()
|
|
||||||
} finally {
|
|
||||||
// image?.close() // Handled by acquiring reader itself or image.use{} if used
|
|
||||||
image?.close() // Close image if not using `use` or if error before `use` finishes
|
|
||||||
}
|
|
||||||
}, imageReaderHandler)
|
|
||||||
|
|
||||||
// 5. Get the Surface to draw onto
|
|
||||||
surface = imageReader.surface ?: throw RuntimeException("Failed to get Surface from ImageReader")
|
|
||||||
|
|
||||||
// 6. Lock Canvas and Draw
|
|
||||||
val canvas: Canvas? = surface.lockHardwareCanvas() // Use hardware accelerated canvas
|
|
||||||
if (canvas != null) {
|
|
||||||
try {
|
|
||||||
// --- Your Drawing Code Here ---
|
|
||||||
val paint = Paint().apply {
|
|
||||||
isAntiAlias = true // Good practice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blue background
|
|
||||||
paint.color = Color.BLUE
|
|
||||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
|
|
||||||
|
|
||||||
// White text
|
|
||||||
paint.color = Color.WHITE
|
|
||||||
paint.textSize = 40f
|
|
||||||
paint.textAlign = Paint.Align.CENTER
|
|
||||||
canvas.drawText("Hello HardwareBuffer! (Kotlin)", width / 2f, height / 2f, paint)
|
|
||||||
// --- End Drawing Code ---
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
// 7. Unlock Canvas and Post
|
|
||||||
surface.unlockCanvasAndPost(canvas)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw RuntimeException("Failed to lock Hardware Canvas")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. Wait for the listener to provide the HardwareBuffer
|
|
||||||
try {
|
|
||||||
// Wait for the buffer; this blocks the current thread.
|
|
||||||
receivedHardwareBuffer = bufferFuture.get(IMAGE_READER_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
|
||||||
// Ownership of receivedHardwareBuffer is now transferred to the caller
|
|
||||||
} catch(timeout: TimeoutException) {
|
|
||||||
Log.e(TAG, "Timeout waiting for HardwareBuffer from ImageReader listener")
|
|
||||||
bufferFuture.cancel(true) // Attempt to cancel listener processing
|
|
||||||
throw timeout // Re-throw
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Failed to draw to HardwareBuffer", e)
|
|
||||||
// Ensure buffer is closed if acquired but an error occurred before returning it
|
|
||||||
receivedHardwareBuffer?.takeUnless { it.isClosed }?.close()
|
|
||||||
return null // Indicate failure
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
// 9. Cleanup
|
|
||||||
try {
|
|
||||||
imageReader?.close() // Also releases the Surface implicitly
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error closing ImageReader", e)
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
handlerThread?.quitSafely()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error quitting HandlerThread", e)
|
|
||||||
}
|
|
||||||
// Note: Do NOT close receivedHardwareBuffer here if returning successfully.
|
|
||||||
// The caller is responsible for closing the returned buffer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the buffer; caller MUST close it.
|
|
||||||
return receivedHardwareBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Example Usage (must be called from appropriate context/thread, like a coroutine) ---
|
|
||||||
/*
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
|
||||||
suspend fun exampleUsage() = withContext(Dispatchers.IO) { // Run blocking code off main thread
|
|
||||||
val myBuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(640, 480)
|
|
||||||
|
|
||||||
// Use the 'use' extension function for automatic closing
|
|
||||||
myBuffer?.use { buffer ->
|
|
||||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
|
||||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
|
||||||
// buffer.close() // 'use' handles this automatically
|
|
||||||
|
|
||||||
} ?: run {
|
|
||||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG,"HardwareBuffer processing finished (buffer closed if obtained).")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.android.filament.externalimg
|
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
|
||||||
import android.app.Activity
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.opengl.Matrix
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.Choreographer
|
|
||||||
import android.view.Surface
|
|
||||||
import android.view.SurfaceView
|
|
||||||
import android.view.animation.LinearInterpolator
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
|
|
||||||
import com.google.android.filament.*
|
|
||||||
import com.google.android.filament.RenderableManager.*
|
|
||||||
import com.google.android.filament.VertexBuffer.*
|
|
||||||
import com.google.android.filament.android.DisplayHelper
|
|
||||||
import com.google.android.filament.android.FilamentHelper
|
|
||||||
import com.google.android.filament.android.UiHelper
|
|
||||||
import com.google.android.filament.utils.ExternalImage
|
|
||||||
import com.google.android.filament.utils.Utils
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.ByteOrder
|
|
||||||
import java.nio.channels.Channels
|
|
||||||
|
|
||||||
import kotlin.math.*
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
|
|
||||||
class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
|
||||||
companion object {
|
|
||||||
init {
|
|
||||||
Filament.init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var TAG = "filament.externalimg"
|
|
||||||
|
|
||||||
private lateinit var surfaceView: SurfaceView
|
|
||||||
private lateinit var uiHelper: UiHelper
|
|
||||||
private lateinit var displayHelper: DisplayHelper
|
|
||||||
private lateinit var choreographer: Choreographer
|
|
||||||
|
|
||||||
private lateinit var engine: Engine
|
|
||||||
private lateinit var renderer: Renderer
|
|
||||||
private lateinit var scene: Scene
|
|
||||||
private lateinit var view: View
|
|
||||||
|
|
||||||
// This is the Filament camera, not the phone camera. :)
|
|
||||||
private lateinit var camera: Camera
|
|
||||||
|
|
||||||
private var filamentTexture: Texture? = null
|
|
||||||
|
|
||||||
// Other Filament objects:
|
|
||||||
private lateinit var material: Material
|
|
||||||
private lateinit var materialInstance: MaterialInstance
|
|
||||||
private lateinit var vertexBuffer: VertexBuffer
|
|
||||||
private lateinit var indexBuffer: IndexBuffer
|
|
||||||
|
|
||||||
// Filament entity representing a renderable object
|
|
||||||
@Entity private var renderable = 0
|
|
||||||
@Entity private var light = 0
|
|
||||||
|
|
||||||
private var myCount : Int = 0
|
|
||||||
|
|
||||||
// A swap chain is Filament's representation of a surface
|
|
||||||
private var swapChain: SwapChain? = null
|
|
||||||
|
|
||||||
// Performs the rendering and schedules new frames
|
|
||||||
private val frameScheduler = FrameCallback()
|
|
||||||
|
|
||||||
private val animator = ValueAnimator.ofFloat(0.0f, 50.0f)
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
Utils.init()
|
|
||||||
|
|
||||||
surfaceView = SurfaceView(this)
|
|
||||||
setContentView(surfaceView)
|
|
||||||
|
|
||||||
choreographer = Choreographer.getInstance()
|
|
||||||
|
|
||||||
displayHelper = DisplayHelper(this)
|
|
||||||
|
|
||||||
setupSurfaceView()
|
|
||||||
setupFilament()
|
|
||||||
setupView()
|
|
||||||
setupScene()
|
|
||||||
|
|
||||||
// ExternalImage.setOnTexture(engine,, texture, buffer, srgb)
|
|
||||||
|
|
||||||
// cameraHelper = CameraHelper(this, engine, materialInstance)
|
|
||||||
// cameraHelper.openCamera()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupSurfaceView() {
|
|
||||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
|
||||||
uiHelper.renderCallback = SurfaceCallback()
|
|
||||||
uiHelper.attachTo(surfaceView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupFilament() {
|
|
||||||
engine = Engine.create()
|
|
||||||
renderer = engine.createRenderer()
|
|
||||||
scene = engine.createScene()
|
|
||||||
view = engine.createView()
|
|
||||||
camera = engine.createCamera(engine.entityManager.create())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupView() {
|
|
||||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
|
||||||
view.camera = camera
|
|
||||||
view.scene = scene
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupScene() {
|
|
||||||
loadMaterial()
|
|
||||||
setupMaterial()
|
|
||||||
createMesh()
|
|
||||||
|
|
||||||
// To create a renderable we first create a generic entity
|
|
||||||
renderable = EntityManager.get().create()
|
|
||||||
|
|
||||||
// We then create a renderable component on that entity
|
|
||||||
// A renderable is made of several primitives; in this case we declare only 1
|
|
||||||
// If we wanted each face of the cube to have a different material, we could
|
|
||||||
// declare 6 primitives (1 per face) and give each of them a different material
|
|
||||||
// instance, setup with different parameters
|
|
||||||
RenderableManager.Builder(1)
|
|
||||||
// Overall bounding box of the renderable
|
|
||||||
.boundingBox(Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f))
|
|
||||||
// Sets the mesh data of the first primitive, 6 faces of 6 indices each
|
|
||||||
.geometry(0, PrimitiveType.TRIANGLES, vertexBuffer, indexBuffer, 0, 6 * 6)
|
|
||||||
// Sets the material of the first primitive
|
|
||||||
.material(0, materialInstance)
|
|
||||||
.build(engine, renderable)
|
|
||||||
|
|
||||||
// Add the entity to the scene to render it
|
|
||||||
scene.addEntity(renderable)
|
|
||||||
|
|
||||||
// We now need a light, let's create a directional light
|
|
||||||
light = EntityManager.get().create()
|
|
||||||
|
|
||||||
// Create a color from a temperature (5,500K)
|
|
||||||
val (r, g, b) = Colors.cct(5_500.0f)
|
|
||||||
LightManager.Builder(LightManager.Type.DIRECTIONAL)
|
|
||||||
.color(r, g, b)
|
|
||||||
// Intensity of the sun in lux on a clear day
|
|
||||||
.intensity(110_000.0f)
|
|
||||||
// The direction is normalized on our behalf
|
|
||||||
.direction(0.0f, -0.5f, -1.0f)
|
|
||||||
.castShadows(true)
|
|
||||||
.build(engine, light)
|
|
||||||
|
|
||||||
// Add the entity to the scene to light it
|
|
||||||
scene.addEntity(light)
|
|
||||||
|
|
||||||
// Set the exposure on the camera, this exposure follows the sunny f/16 rule
|
|
||||||
// Since we've defined a light that has the same intensity as the sun, it
|
|
||||||
// guarantees a proper exposure
|
|
||||||
camera.setExposure(16.0f, 1.0f / 125.0f, 100.0f)
|
|
||||||
|
|
||||||
// Move the camera back to see the object
|
|
||||||
camera.lookAt(0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
|
||||||
|
|
||||||
startAnimation()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadMaterial() {
|
|
||||||
readUncompressedAsset("materials/lit.filamat").let {
|
|
||||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupMaterial() {
|
|
||||||
materialInstance = material.createInstance()
|
|
||||||
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
|
|
||||||
materialInstance.setParameter("roughness", 0.3f)
|
|
||||||
|
|
||||||
val textureTransform = FloatArray(16)
|
|
||||||
Matrix.setIdentityM(textureTransform, 0)
|
|
||||||
|
|
||||||
filamentTexture = Texture.Builder()
|
|
||||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
|
||||||
.width(400)
|
|
||||||
.height(400)
|
|
||||||
.format(Texture.InternalFormat.RGBA8)
|
|
||||||
.build(engine)
|
|
||||||
|
|
||||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
|
||||||
materialInstance.setParameter("videoTexture", filamentTexture!!, sampler)
|
|
||||||
materialInstance.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createMesh() {
|
|
||||||
val floatSize = 4
|
|
||||||
val shortSize = 2
|
|
||||||
// A vertex is a position + a tangent frame:
|
|
||||||
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
|
|
||||||
val vertexSize = 3 * floatSize + 4 * floatSize
|
|
||||||
|
|
||||||
// Define a vertex and a function to put a vertex in a ByteBuffer
|
|
||||||
@Suppress("ArrayInDataClass")
|
|
||||||
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
|
|
||||||
fun ByteBuffer.put(v: Vertex): ByteBuffer {
|
|
||||||
putFloat(v.x)
|
|
||||||
putFloat(v.y)
|
|
||||||
putFloat(v.z)
|
|
||||||
v.tangents.forEach { putFloat(it) }
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6 faces, 4 vertices per face
|
|
||||||
val vertexCount = 6 * 4
|
|
||||||
|
|
||||||
// Create tangent frames, one per face
|
|
||||||
val tfPX = FloatArray(4)
|
|
||||||
val tfNX = FloatArray(4)
|
|
||||||
val tfPY = FloatArray(4)
|
|
||||||
val tfNY = FloatArray(4)
|
|
||||||
val tfPZ = FloatArray(4)
|
|
||||||
val tfNZ = FloatArray(4)
|
|
||||||
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, tfPX)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, tfNX)
|
|
||||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, tfPY)
|
|
||||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, tfNY)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, tfPZ)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, tfNZ)
|
|
||||||
|
|
||||||
val vertexData = ByteBuffer.allocate(vertexCount * vertexSize)
|
|
||||||
// It is important to respect the native byte order
|
|
||||||
.order(ByteOrder.nativeOrder())
|
|
||||||
// Face -Z
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNZ))
|
|
||||||
// Face +X
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPX))
|
|
||||||
// Face +Z
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPZ))
|
|
||||||
// Face -X
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNX))
|
|
||||||
// Face -Y
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNY))
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNY))
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNY))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfNY))
|
|
||||||
// Face +Y
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfPY))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPY))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPY))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPY))
|
|
||||||
// Make sure the cursor is pointing in the right place in the byte buffer
|
|
||||||
.flip()
|
|
||||||
|
|
||||||
// Declare the layout of our mesh
|
|
||||||
vertexBuffer = VertexBuffer.Builder()
|
|
||||||
.bufferCount(1)
|
|
||||||
.vertexCount(vertexCount)
|
|
||||||
// Because we interleave position and color data we must specify offset and stride
|
|
||||||
// We could use de-interleaved data by declaring two buffers and giving each
|
|
||||||
// attribute a different buffer index
|
|
||||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
|
|
||||||
.attribute(VertexAttribute.TANGENTS, 0, AttributeType.FLOAT4, 3 * floatSize, vertexSize)
|
|
||||||
.build(engine)
|
|
||||||
|
|
||||||
// Feed the vertex data to the mesh
|
|
||||||
// We only set 1 buffer because the data is interleaved
|
|
||||||
vertexBuffer.setBufferAt(engine, 0, vertexData)
|
|
||||||
|
|
||||||
// Create the indices
|
|
||||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
|
||||||
.order(ByteOrder.nativeOrder())
|
|
||||||
repeat(6) {
|
|
||||||
val i = (it * 4).toShort()
|
|
||||||
indexData
|
|
||||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
|
||||||
.putShort(i).putShort((i + 2).toShort()).putShort((i + 3).toShort())
|
|
||||||
}
|
|
||||||
indexData.flip()
|
|
||||||
|
|
||||||
// 6 faces, 2 triangles per face,
|
|
||||||
indexBuffer = IndexBuffer.Builder()
|
|
||||||
.indexCount(vertexCount * 2)
|
|
||||||
.bufferType(IndexBuffer.Builder.IndexType.USHORT)
|
|
||||||
.build(engine)
|
|
||||||
indexBuffer.setBuffer(engine, indexData)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startAnimation() {
|
|
||||||
// Animate the triangle
|
|
||||||
animator.interpolator = LinearInterpolator()
|
|
||||||
animator.duration = 6000
|
|
||||||
animator.repeatMode = ValueAnimator.RESTART
|
|
||||||
animator.repeatCount = ValueAnimator.INFINITE
|
|
||||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
|
||||||
val transformMatrix = FloatArray(16)
|
|
||||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
|
||||||
val t = animator.animatedValue as Float
|
|
||||||
val radians = sin(t) * 3.0f * PI.toFloat()
|
|
||||||
Matrix.setRotateM(transformMatrix, 0, radians, 0.0f, 1.0f, 0.0f)
|
|
||||||
val tcm = engine.transformManager
|
|
||||||
tcm.setTransform(tcm.getInstance(renderable), transformMatrix)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
animator.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
choreographer.postFrameCallback(frameScheduler)
|
|
||||||
animator.start()
|
|
||||||
// cameraHelper.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
choreographer.removeFrameCallback(frameScheduler)
|
|
||||||
animator.cancel()
|
|
||||||
// cameraHelper.onPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
|
|
||||||
// Stop the animation and any pending frame
|
|
||||||
choreographer.removeFrameCallback(frameScheduler)
|
|
||||||
animator.cancel()
|
|
||||||
|
|
||||||
// Always detach the surface before destroying the engine
|
|
||||||
uiHelper.detach()
|
|
||||||
|
|
||||||
// Cleanup all resources
|
|
||||||
engine.destroyEntity(light)
|
|
||||||
engine.destroyEntity(renderable)
|
|
||||||
engine.destroyRenderer(renderer)
|
|
||||||
engine.destroyVertexBuffer(vertexBuffer)
|
|
||||||
engine.destroyIndexBuffer(indexBuffer)
|
|
||||||
engine.destroyMaterialInstance(materialInstance)
|
|
||||||
engine.destroyMaterial(material)
|
|
||||||
engine.destroyView(view)
|
|
||||||
engine.destroyScene(scene)
|
|
||||||
engine.destroyCameraComponent(camera.entity)
|
|
||||||
|
|
||||||
// Engine.destroyEntity() destroys Filament related resources only
|
|
||||||
// (components), not the entity itself
|
|
||||||
val entityManager = EntityManager.get()
|
|
||||||
entityManager.destroy(light)
|
|
||||||
entityManager.destroy(renderable)
|
|
||||||
entityManager.destroy(camera.entity)
|
|
||||||
|
|
||||||
// Destroying the engine will free up any resource you may have forgotten
|
|
||||||
// to destroy, but it's recommended to do the cleanup properly
|
|
||||||
engine.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class FrameCallback : Choreographer.FrameCallback {
|
|
||||||
override fun doFrame(frameTimeNanos: Long) {
|
|
||||||
// Schedule the next frame
|
|
||||||
choreographer.postFrameCallback(this)
|
|
||||||
|
|
||||||
// This check guarantees that we have a swap chain
|
|
||||||
if (uiHelper.isReadyToRender) {
|
|
||||||
|
|
||||||
if (myCount < 1) {
|
|
||||||
val mybuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(400, 400)
|
|
||||||
mybuffer?.use { buffer : HardwareBuffer ->
|
|
||||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
|
||||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
|
||||||
// buffer.close() // 'use' handles this automatically
|
|
||||||
ExternalImage.setOnTexture(engine, filamentTexture!!, buffer, false)
|
|
||||||
|
|
||||||
} ?: run {
|
|
||||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myCount ++;
|
|
||||||
|
|
||||||
// cameraHelper.pushExternalImageToFilament()
|
|
||||||
|
|
||||||
// If beginFrame() returns false you should skip the frame
|
|
||||||
// This means you are sending frames too quickly to the GPU
|
|
||||||
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
|
|
||||||
renderer.render(view)
|
|
||||||
renderer.endFrame()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SurfaceCallback : UiHelper.RendererCallback {
|
|
||||||
override fun onNativeWindowChanged(surface: Surface) {
|
|
||||||
swapChain?.let { engine.destroySwapChain(it) }
|
|
||||||
swapChain = engine.createSwapChain(surface)
|
|
||||||
displayHelper.attach(renderer, surfaceView.display)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromSurface() {
|
|
||||||
displayHelper.detach()
|
|
||||||
swapChain?.let {
|
|
||||||
engine.destroySwapChain(it)
|
|
||||||
// Required to ensure we don't return before Filament is done executing the
|
|
||||||
// destroySwapChain command, otherwise Android might destroy the Surface
|
|
||||||
// too early
|
|
||||||
engine.flushAndWait()
|
|
||||||
swapChain = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResized(width: Int, height: Int) {
|
|
||||||
val aspect = width.toDouble() / height.toDouble()
|
|
||||||
camera.setProjection(45.0, aspect, 0.1, 20.0, Camera.Fov.VERTICAL)
|
|
||||||
|
|
||||||
view.viewport = Viewport(0, 0, width, height)
|
|
||||||
|
|
||||||
FilamentHelper.synchronizePendingFrames(engine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun readUncompressedAsset(@Suppress("SameParameterValue") assetName: String): ByteBuffer {
|
|
||||||
assets.openFd(assetName).use { fd ->
|
|
||||||
val input = fd.createInputStream()
|
|
||||||
val dst = ByteBuffer.allocate(fd.length.toInt())
|
|
||||||
|
|
||||||
val src = Channels.newChannel(input)
|
|
||||||
src.read(dst)
|
|
||||||
src.close()
|
|
||||||
|
|
||||||
return dst.apply { rewind() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
|
||||||
// if (!cameraHelper.onRequestPermissionsResult(requestCode, grantResults)) {
|
|
||||||
// this.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,446 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.android.filament.externalimg
|
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
|
||||||
import android.app.Activity
|
|
||||||
import android.hardware.HardwareBuffer
|
|
||||||
import android.opengl.Matrix
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.Choreographer
|
|
||||||
import android.view.Surface
|
|
||||||
import android.view.SurfaceView
|
|
||||||
import android.view.animation.LinearInterpolator
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
|
|
||||||
import com.google.android.filament.*
|
|
||||||
import com.google.android.filament.RenderableManager.*
|
|
||||||
import com.google.android.filament.VertexBuffer.*
|
|
||||||
import com.google.android.filament.android.DisplayHelper
|
|
||||||
import com.google.android.filament.android.FilamentHelper
|
|
||||||
import com.google.android.filament.android.UiHelper
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.ByteOrder
|
|
||||||
import java.nio.channels.Channels
|
|
||||||
|
|
||||||
import kotlin.math.*
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
|
|
||||||
class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
|
||||||
companion object {
|
|
||||||
init {
|
|
||||||
Filament.init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var TAG = "filament.externalimg"
|
|
||||||
|
|
||||||
private lateinit var surfaceView: SurfaceView
|
|
||||||
private lateinit var uiHelper: UiHelper
|
|
||||||
private lateinit var displayHelper: DisplayHelper
|
|
||||||
private lateinit var choreographer: Choreographer
|
|
||||||
|
|
||||||
private lateinit var engine: Engine
|
|
||||||
private lateinit var renderer: Renderer
|
|
||||||
private lateinit var scene: Scene
|
|
||||||
private lateinit var view: View
|
|
||||||
|
|
||||||
// This is the Filament camera, not the phone camera. :)
|
|
||||||
private lateinit var camera: Camera
|
|
||||||
|
|
||||||
// Other Filament objects:
|
|
||||||
private lateinit var material: Material
|
|
||||||
private lateinit var materialInstance: MaterialInstance
|
|
||||||
private lateinit var vertexBuffer: VertexBuffer
|
|
||||||
private lateinit var indexBuffer: IndexBuffer
|
|
||||||
|
|
||||||
// Filament entity representing a renderable object
|
|
||||||
@Entity private var renderable = 0
|
|
||||||
@Entity private var light = 0
|
|
||||||
|
|
||||||
private var myCount : Int = 0
|
|
||||||
|
|
||||||
// A swap chain is Filament's representation of a surface
|
|
||||||
private var swapChain: SwapChain? = null
|
|
||||||
|
|
||||||
// Performs the rendering and schedules new frames
|
|
||||||
private val frameScheduler = FrameCallback()
|
|
||||||
|
|
||||||
private val animator = ValueAnimator.ofFloat(0.0f, 50.0f)
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
surfaceView = SurfaceView(this)
|
|
||||||
setContentView(surfaceView)
|
|
||||||
|
|
||||||
choreographer = Choreographer.getInstance()
|
|
||||||
|
|
||||||
displayHelper = DisplayHelper(this)
|
|
||||||
|
|
||||||
setupSurfaceView()
|
|
||||||
setupFilament()
|
|
||||||
setupView()
|
|
||||||
setupScene()
|
|
||||||
|
|
||||||
// cameraHelper = CameraHelper(this, engine, materialInstance)
|
|
||||||
// cameraHelper.openCamera()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupSurfaceView() {
|
|
||||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
|
||||||
uiHelper.renderCallback = SurfaceCallback()
|
|
||||||
uiHelper.attachTo(surfaceView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupFilament() {
|
|
||||||
engine = Engine.create()
|
|
||||||
renderer = engine.createRenderer()
|
|
||||||
scene = engine.createScene()
|
|
||||||
view = engine.createView()
|
|
||||||
camera = engine.createCamera(engine.entityManager.create())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupView() {
|
|
||||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
|
||||||
view.camera = camera
|
|
||||||
view.scene = scene
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupScene() {
|
|
||||||
loadMaterial()
|
|
||||||
setupMaterial()
|
|
||||||
createMesh()
|
|
||||||
|
|
||||||
// To create a renderable we first create a generic entity
|
|
||||||
renderable = EntityManager.get().create()
|
|
||||||
|
|
||||||
// We then create a renderable component on that entity
|
|
||||||
// A renderable is made of several primitives; in this case we declare only 1
|
|
||||||
// If we wanted each face of the cube to have a different material, we could
|
|
||||||
// declare 6 primitives (1 per face) and give each of them a different material
|
|
||||||
// instance, setup with different parameters
|
|
||||||
RenderableManager.Builder(1)
|
|
||||||
// Overall bounding box of the renderable
|
|
||||||
.boundingBox(Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f))
|
|
||||||
// Sets the mesh data of the first primitive, 6 faces of 6 indices each
|
|
||||||
.geometry(0, PrimitiveType.TRIANGLES, vertexBuffer, indexBuffer, 0, 6 * 6)
|
|
||||||
// Sets the material of the first primitive
|
|
||||||
.material(0, materialInstance)
|
|
||||||
.build(engine, renderable)
|
|
||||||
|
|
||||||
// Add the entity to the scene to render it
|
|
||||||
scene.addEntity(renderable)
|
|
||||||
|
|
||||||
// We now need a light, let's create a directional light
|
|
||||||
light = EntityManager.get().create()
|
|
||||||
|
|
||||||
// Create a color from a temperature (5,500K)
|
|
||||||
val (r, g, b) = Colors.cct(5_500.0f)
|
|
||||||
LightManager.Builder(LightManager.Type.DIRECTIONAL)
|
|
||||||
.color(r, g, b)
|
|
||||||
// Intensity of the sun in lux on a clear day
|
|
||||||
.intensity(110_000.0f)
|
|
||||||
// The direction is normalized on our behalf
|
|
||||||
.direction(0.0f, -0.5f, -1.0f)
|
|
||||||
.castShadows(true)
|
|
||||||
.build(engine, light)
|
|
||||||
|
|
||||||
// Add the entity to the scene to light it
|
|
||||||
scene.addEntity(light)
|
|
||||||
|
|
||||||
// Set the exposure on the camera, this exposure follows the sunny f/16 rule
|
|
||||||
// Since we've defined a light that has the same intensity as the sun, it
|
|
||||||
// guarantees a proper exposure
|
|
||||||
camera.setExposure(16.0f, 1.0f / 125.0f, 100.0f)
|
|
||||||
|
|
||||||
// Move the camera back to see the object
|
|
||||||
camera.lookAt(0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
|
||||||
|
|
||||||
startAnimation()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadMaterial() {
|
|
||||||
readUncompressedAsset("materials/lit.filamat").let {
|
|
||||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupMaterial() {
|
|
||||||
materialInstance = material.createInstance()
|
|
||||||
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
|
|
||||||
materialInstance.setParameter("roughness", 0.3f)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createMesh() {
|
|
||||||
val floatSize = 4
|
|
||||||
val shortSize = 2
|
|
||||||
// A vertex is a position + a tangent frame:
|
|
||||||
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
|
|
||||||
val vertexSize = 3 * floatSize + 4 * floatSize
|
|
||||||
|
|
||||||
// Define a vertex and a function to put a vertex in a ByteBuffer
|
|
||||||
@Suppress("ArrayInDataClass")
|
|
||||||
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
|
|
||||||
fun ByteBuffer.put(v: Vertex): ByteBuffer {
|
|
||||||
putFloat(v.x)
|
|
||||||
putFloat(v.y)
|
|
||||||
putFloat(v.z)
|
|
||||||
v.tangents.forEach { putFloat(it) }
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6 faces, 4 vertices per face
|
|
||||||
val vertexCount = 6 * 4
|
|
||||||
|
|
||||||
// Create tangent frames, one per face
|
|
||||||
val tfPX = FloatArray(4)
|
|
||||||
val tfNX = FloatArray(4)
|
|
||||||
val tfPY = FloatArray(4)
|
|
||||||
val tfNY = FloatArray(4)
|
|
||||||
val tfPZ = FloatArray(4)
|
|
||||||
val tfNZ = FloatArray(4)
|
|
||||||
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, tfPX)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, tfNX)
|
|
||||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, tfPY)
|
|
||||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, tfNY)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, tfPZ)
|
|
||||||
MathUtils.packTangentFrame( 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, tfNZ)
|
|
||||||
|
|
||||||
val vertexData = ByteBuffer.allocate(vertexCount * vertexSize)
|
|
||||||
// It is important to respect the native byte order
|
|
||||||
.order(ByteOrder.nativeOrder())
|
|
||||||
// Face -Z
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfNZ))
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNZ))
|
|
||||||
// Face +X
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPX))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPX))
|
|
||||||
// Face +Z
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPZ))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPZ))
|
|
||||||
// Face -X
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNX))
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNX))
|
|
||||||
// Face -Y
|
|
||||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNY))
|
|
||||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNY))
|
|
||||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNY))
|
|
||||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfNY))
|
|
||||||
// Face +Y
|
|
||||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfPY))
|
|
||||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPY))
|
|
||||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPY))
|
|
||||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPY))
|
|
||||||
// Make sure the cursor is pointing in the right place in the byte buffer
|
|
||||||
.flip()
|
|
||||||
|
|
||||||
// Declare the layout of our mesh
|
|
||||||
vertexBuffer = VertexBuffer.Builder()
|
|
||||||
.bufferCount(1)
|
|
||||||
.vertexCount(vertexCount)
|
|
||||||
// Because we interleave position and color data we must specify offset and stride
|
|
||||||
// We could use de-interleaved data by declaring two buffers and giving each
|
|
||||||
// attribute a different buffer index
|
|
||||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
|
|
||||||
.attribute(VertexAttribute.TANGENTS, 0, AttributeType.FLOAT4, 3 * floatSize, vertexSize)
|
|
||||||
.build(engine)
|
|
||||||
|
|
||||||
// Feed the vertex data to the mesh
|
|
||||||
// We only set 1 buffer because the data is interleaved
|
|
||||||
vertexBuffer.setBufferAt(engine, 0, vertexData)
|
|
||||||
|
|
||||||
// Create the indices
|
|
||||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
|
||||||
.order(ByteOrder.nativeOrder())
|
|
||||||
repeat(6) {
|
|
||||||
val i = (it * 4).toShort()
|
|
||||||
indexData
|
|
||||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
|
||||||
.putShort(i).putShort((i + 2).toShort()).putShort((i + 3).toShort())
|
|
||||||
}
|
|
||||||
indexData.flip()
|
|
||||||
|
|
||||||
// 6 faces, 2 triangles per face,
|
|
||||||
indexBuffer = IndexBuffer.Builder()
|
|
||||||
.indexCount(vertexCount * 2)
|
|
||||||
.bufferType(IndexBuffer.Builder.IndexType.USHORT)
|
|
||||||
.build(engine)
|
|
||||||
indexBuffer.setBuffer(engine, indexData)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startAnimation() {
|
|
||||||
// Animate the triangle
|
|
||||||
animator.interpolator = LinearInterpolator()
|
|
||||||
animator.duration = 6000
|
|
||||||
animator.repeatMode = ValueAnimator.RESTART
|
|
||||||
animator.repeatCount = ValueAnimator.INFINITE
|
|
||||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
|
||||||
val transformMatrix = FloatArray(16)
|
|
||||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
|
||||||
val t = animator.animatedValue as Float
|
|
||||||
val radians = sin(t) * 3.0f * PI.toFloat()
|
|
||||||
Matrix.setRotateM(transformMatrix, 0, radians, 0.0f, 1.0f, 0.0f)
|
|
||||||
val tcm = engine.transformManager
|
|
||||||
tcm.setTransform(tcm.getInstance(renderable), transformMatrix)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
animator.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
choreographer.postFrameCallback(frameScheduler)
|
|
||||||
animator.start()
|
|
||||||
// cameraHelper.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
choreographer.removeFrameCallback(frameScheduler)
|
|
||||||
animator.cancel()
|
|
||||||
// cameraHelper.onPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
|
|
||||||
// Stop the animation and any pending frame
|
|
||||||
choreographer.removeFrameCallback(frameScheduler)
|
|
||||||
animator.cancel()
|
|
||||||
|
|
||||||
// Always detach the surface before destroying the engine
|
|
||||||
uiHelper.detach()
|
|
||||||
|
|
||||||
// Cleanup all resources
|
|
||||||
engine.destroyEntity(light)
|
|
||||||
engine.destroyEntity(renderable)
|
|
||||||
engine.destroyRenderer(renderer)
|
|
||||||
engine.destroyVertexBuffer(vertexBuffer)
|
|
||||||
engine.destroyIndexBuffer(indexBuffer)
|
|
||||||
engine.destroyMaterialInstance(materialInstance)
|
|
||||||
engine.destroyMaterial(material)
|
|
||||||
engine.destroyView(view)
|
|
||||||
engine.destroyScene(scene)
|
|
||||||
engine.destroyCameraComponent(camera.entity)
|
|
||||||
|
|
||||||
// Engine.destroyEntity() destroys Filament related resources only
|
|
||||||
// (components), not the entity itself
|
|
||||||
val entityManager = EntityManager.get()
|
|
||||||
entityManager.destroy(light)
|
|
||||||
entityManager.destroy(renderable)
|
|
||||||
entityManager.destroy(camera.entity)
|
|
||||||
|
|
||||||
// Destroying the engine will free up any resource you may have forgotten
|
|
||||||
// to destroy, but it's recommended to do the cleanup properly
|
|
||||||
engine.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class FrameCallback : Choreographer.FrameCallback {
|
|
||||||
override fun doFrame(frameTimeNanos: Long) {
|
|
||||||
// Schedule the next frame
|
|
||||||
choreographer.postFrameCallback(this)
|
|
||||||
|
|
||||||
// This check guarantees that we have a swap chain
|
|
||||||
if (uiHelper.isReadyToRender) {
|
|
||||||
|
|
||||||
if (myCount < 1) {
|
|
||||||
val mybuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(400, 400)
|
|
||||||
mybuffer?.use { buffer : HardwareBuffer ->
|
|
||||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
|
||||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
|
||||||
// buffer.close() // 'use' handles this automatically
|
|
||||||
|
|
||||||
} ?: run {
|
|
||||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myCount ++;
|
|
||||||
|
|
||||||
// cameraHelper.pushExternalImageToFilament()
|
|
||||||
|
|
||||||
// If beginFrame() returns false you should skip the frame
|
|
||||||
// This means you are sending frames too quickly to the GPU
|
|
||||||
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
|
|
||||||
renderer.render(view)
|
|
||||||
renderer.endFrame()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class SurfaceCallback : UiHelper.RendererCallback {
|
|
||||||
override fun onNativeWindowChanged(surface: Surface) {
|
|
||||||
swapChain?.let { engine.destroySwapChain(it) }
|
|
||||||
swapChain = engine.createSwapChain(surface)
|
|
||||||
displayHelper.attach(renderer, surfaceView.display)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromSurface() {
|
|
||||||
displayHelper.detach()
|
|
||||||
swapChain?.let {
|
|
||||||
engine.destroySwapChain(it)
|
|
||||||
// Required to ensure we don't return before Filament is done executing the
|
|
||||||
// destroySwapChain command, otherwise Android might destroy the Surface
|
|
||||||
// too early
|
|
||||||
engine.flushAndWait()
|
|
||||||
swapChain = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResized(width: Int, height: Int) {
|
|
||||||
val aspect = width.toDouble() / height.toDouble()
|
|
||||||
camera.setProjection(45.0, aspect, 0.1, 20.0, Camera.Fov.VERTICAL)
|
|
||||||
|
|
||||||
view.viewport = Viewport(0, 0, width, height)
|
|
||||||
|
|
||||||
FilamentHelper.synchronizePendingFrames(engine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun readUncompressedAsset(@Suppress("SameParameterValue") assetName: String): ByteBuffer {
|
|
||||||
assets.openFd(assetName).use { fd ->
|
|
||||||
val input = fd.createInputStream()
|
|
||||||
val dst = ByteBuffer.allocate(fd.length.toInt())
|
|
||||||
|
|
||||||
val src = Channels.newChannel(input)
|
|
||||||
src.read(dst)
|
|
||||||
src.close()
|
|
||||||
|
|
||||||
return dst.apply { rewind() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
|
||||||
// if (!cameraHelper.onRequestPermissionsResult(requestCode, grantResults)) {
|
|
||||||
// this.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Simple lit material that defines 3 parameters:
|
|
||||||
// - baseColor
|
|
||||||
// - roughness
|
|
||||||
// - metallic
|
|
||||||
//
|
|
||||||
// These parameters can be used by the application to change the appearance of the material.
|
|
||||||
//
|
|
||||||
// This source material must be compiled to a binary material using the matc tool.
|
|
||||||
// The command used to compile this material is:
|
|
||||||
// matc -p mobile -a opengl -o app/src/main/assets/lit.filamat app/src/materials/lit.mat
|
|
||||||
//
|
|
||||||
// See build.gradle for an example of how to compile materials automatically
|
|
||||||
// Please refer to the documentation for more information about matc and the materials system.
|
|
||||||
|
|
||||||
material {
|
|
||||||
name : lit,
|
|
||||||
|
|
||||||
// Dynamic lighting is enabled on this material
|
|
||||||
shadingModel : lit,
|
|
||||||
|
|
||||||
// We don't need to declare a "requires" array, lit materials
|
|
||||||
// always requires the "tangents" vertex attribute (the normal
|
|
||||||
// is required for lighting, tangent/bitangent for normal mapping
|
|
||||||
// and anisotropy)
|
|
||||||
|
|
||||||
// Custom vertex shader outputs
|
|
||||||
variables : [
|
|
||||||
uv
|
|
||||||
],
|
|
||||||
|
|
||||||
// List of parameters exposed by this material
|
|
||||||
parameters : [
|
|
||||||
// The color must be passed in linear space, not sRGB
|
|
||||||
{
|
|
||||||
type : float3,
|
|
||||||
name : baseColor
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type : float,
|
|
||||||
name : roughness
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type : samplerExternal,
|
|
||||||
name : videoTexture
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type : mat4,
|
|
||||||
name : textureTransform
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex {
|
|
||||||
void materialVertex(inout MaterialVertexInputs material) {
|
|
||||||
material.uv = 0.5 * (getPosition() + vec4(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment {
|
|
||||||
void material(inout MaterialInputs material) {
|
|
||||||
prepareMaterial(material);
|
|
||||||
material.roughness = materialParams.roughness;
|
|
||||||
material.metallic = 0.0;
|
|
||||||
|
|
||||||
// Apply the video stream to the +Z face on the cube.
|
|
||||||
if (variable_uv.z >= 1.0) {
|
|
||||||
vec2 uv = (materialParams.textureTransform * vec4(variable_uv.xy, 0, 1)).xy;
|
|
||||||
material.baseColor.rgb = inverseTonemapSRGB(texture(materialParams_videoTexture, uv).rgb);
|
|
||||||
} else {
|
|
||||||
material.baseColor.rgb = materialParams.baseColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108">
|
|
||||||
<path
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
|
||||||
android:strokeColor="#00000000"
|
|
||||||
android:strokeWidth="1">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:endX="78.5885"
|
|
||||||
android:endY="90.9159"
|
|
||||||
android:startX="48.7653"
|
|
||||||
android:startY="61.0927"
|
|
||||||
android:type="linear">
|
|
||||||
<item
|
|
||||||
android:color="#44000000"
|
|
||||||
android:offset="0.0"/>
|
|
||||||
<item
|
|
||||||
android:color="#00000000"
|
|
||||||
android:offset="1.0"/>
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFF"
|
|
||||||
android:fillType="nonZero"
|
|
||||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
|
||||||
android:strokeColor="#00000000"
|
|
||||||
android:strokeWidth="1"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108">
|
|
||||||
<path
|
|
||||||
android:fillColor="#26A69A"
|
|
||||||
android:pathData="M0,0h108v108h-108z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M9,0L9,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,0L19,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,0L29,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,0L39,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,0L49,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,0L59,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,0L69,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,0L79,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M89,0L89,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M99,0L99,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,9L108,9"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,19L108,19"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,29L108,29"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,39L108,39"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,49L108,49"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,59L108,59"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,69L108,69"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,79L108,79"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,89L108,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,99L108,99"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,29L89,29"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,39L89,39"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,49L89,49"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,59L89,59"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,69L89,69"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,79L89,79"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,19L29,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,19L39,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,19L49,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,19L59,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,19L69,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,19L79,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="colorPrimary">#3F51B5</color>
|
|
||||||
<color name="colorPrimaryDark">#303F9F</color>
|
|
||||||
<color name="colorAccent">#FF4081</color>
|
|
||||||
</resources>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<resources>
|
|
||||||
<string name="app_name">External Image</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<resources>
|
|
||||||
<string name="app_name">Hello Camera</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -18,6 +18,5 @@ include ':samples:sample-stream-test'
|
|||||||
include ':samples:sample-texture-view'
|
include ':samples:sample-texture-view'
|
||||||
include ':samples:sample-textured-object'
|
include ':samples:sample-textured-object'
|
||||||
include ':samples:sample-transparent-view'
|
include ':samples:sample-transparent-view'
|
||||||
include ':samples:sample-external-image'
|
|
||||||
|
|
||||||
rootProject.name = 'filament'
|
rootProject.name = 'filament'
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
|||||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
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 update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ This document is part of the [Filament project](https://github.com/google/filame
|
|||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
- [Romain Guy](https://github.com/romainguy), [@romainguy](https://twitter.com/romainguy)
|
- [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
|
# Overview
|
||||||
|
|
||||||
@@ -78,27 +78,26 @@ in table [standardProperties].
|
|||||||
Property | Definition
|
Property | Definition
|
||||||
-----------------------:|:---------------------
|
-----------------------:|:---------------------
|
||||||
**baseColor** | Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
|
**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)
|
**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
|
**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
|
**sheenColor** | Strength of the sheen layer
|
||||||
**sheenRoughness** | Perceived smoothness or roughness 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_)
|
**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
|
**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]
|
[Table [standardProperties]: Properties of the standard model]
|
||||||
|
|
||||||
The type and range of each property is described in table [standardPropertiesTypes].
|
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
|
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.
|
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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||||
material {
|
material {
|
||||||
parameters : [
|
parameters : [
|
||||||
@@ -1306,7 +1302,7 @@ Type
|
|||||||
: array of `string`
|
: array of `string`
|
||||||
|
|
||||||
Value
|
Value
|
||||||
: Up to 5 strings, each must be a valid GLSL identifier.
|
: Up to 4 strings, each must be a valid GLSL identifier.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
: Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
: 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
|
particular if `default` is specified the default precision is used is the fragment shader
|
||||||
(`mediump`) and in the vertex shader (`highp`).
|
(`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
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||||
material {
|
material {
|
||||||
name : Skybox,
|
name : Skybox,
|
||||||
|
|||||||
@@ -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/PlatformCocoaTouchGL.mm)
|
||||||
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
|
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformOSMesa.cpp)
|
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
|
||||||
else()
|
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
|
||||||
list(APPEND SRCS src/opengl/platforms/CocoaExternalImage.mm)
|
|
||||||
endif()
|
|
||||||
elseif (WEBGL)
|
elseif (WEBGL)
|
||||||
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
||||||
elseif (LINUX)
|
elseif (LINUX)
|
||||||
@@ -177,12 +173,10 @@ endif()
|
|||||||
if (FILAMENT_SUPPORTS_VULKAN)
|
if (FILAMENT_SUPPORTS_VULKAN)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
include/backend/platforms/VulkanPlatform.h
|
include/backend/platforms/VulkanPlatform.h
|
||||||
src/vulkan/VulkanDescriptorSetCache.cpp
|
src/vulkan/caching/VulkanDescriptorSetManager.cpp
|
||||||
src/vulkan/VulkanDescriptorSetCache.h
|
src/vulkan/caching/VulkanDescriptorSetManager.h
|
||||||
src/vulkan/VulkanDescriptorSetLayoutCache.cpp
|
src/vulkan/caching/VulkanPipelineLayoutCache.cpp
|
||||||
src/vulkan/VulkanDescriptorSetLayoutCache.h
|
src/vulkan/caching/VulkanPipelineLayoutCache.h
|
||||||
src/vulkan/VulkanPipelineLayoutCache.cpp
|
|
||||||
src/vulkan/VulkanPipelineLayoutCache.h
|
|
||||||
src/vulkan/memory/ResourceManager.cpp
|
src/vulkan/memory/ResourceManager.cpp
|
||||||
src/vulkan/memory/ResourceManager.h
|
src/vulkan/memory/ResourceManager.h
|
||||||
src/vulkan/memory/ResourcePointer.h
|
src/vulkan/memory/ResourcePointer.h
|
||||||
@@ -248,31 +242,11 @@ endif()
|
|||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
include/backend/platforms/WebGPUPlatform.h
|
|
||||||
src/webgpu/platform/WebGPUPlatform.cpp
|
|
||||||
src/webgpu/WebGPUConstants.h
|
|
||||||
src/webgpu/WebGPUDriver.cpp
|
src/webgpu/WebGPUDriver.cpp
|
||||||
src/webgpu/WebGPUDriver.h
|
src/webgpu/WebGPUDriver.h
|
||||||
|
src/webgpu/WebGPUPlatform.cpp
|
||||||
|
src/webgpu/WebGPUPlatform.h
|
||||||
)
|
)
|
||||||
if (WIN32)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp)
|
|
||||||
elseif (LINUX)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformLinux.cpp)
|
|
||||||
elseif (APPLE OR IOS)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformApple.mm)
|
|
||||||
elseif (ANDROID)
|
|
||||||
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformAndroid.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (TNT_DEV)
|
|
||||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT ON)
|
|
||||||
else()
|
|
||||||
set(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING
|
|
||||||
"Enable immediate_error_handling for the WebGPU backend Dawn implementation"
|
|
||||||
${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING_DEFAULT})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
@@ -422,12 +396,9 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS
|
|||||||
-Wl,--exclude-libs,bluegl
|
-Wl,--exclude-libs,bluegl
|
||||||
)
|
)
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_OSMESA)
|
if (LINUX AND FILAMENT_SUPPORTS_OSMESA)
|
||||||
if (LINUX)
|
set(OSMESA_COMPILE_FLAGS
|
||||||
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL)
|
-I${FILAMENT_OSMESA_PATH}/include/GL)
|
||||||
elseif (APPLE)
|
|
||||||
set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
@@ -462,10 +433,6 @@ if (FILAMENT_SUPPORTS_METAL)
|
|||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_METAL_PROFILING}>:FILAMENT_METAL_PROFILING>)
|
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_METAL_PROFILING}>:FILAMENT_METAL_PROFILING>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
|
||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(${TARGET} PRIVATE
|
target_link_libraries(${TARGET} PRIVATE
|
||||||
${OSMESA_LINKER_FLAGS}
|
${OSMESA_LINKER_FLAGS}
|
||||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||||
|
|||||||
@@ -126,10 +126,6 @@ static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
|||||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||||
|
|
||||||
static constexpr uint8_t EXTERNAL_SAMPLER_DATA_INDEX_UNUSED =
|
|
||||||
uint8_t(-1);// Case where the descriptor set binding isnt using any external sampler state
|
|
||||||
// and therefore doesn't have a valid entry.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the backend's feature levels.
|
* Defines the backend's feature levels.
|
||||||
*/
|
*/
|
||||||
@@ -256,19 +252,21 @@ struct DescriptorSetLayoutBinding {
|
|||||||
DescriptorFlags flags = DescriptorFlags::NONE;
|
DescriptorFlags flags = DescriptorFlags::NONE;
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
|
|
||||||
uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
|
||||||
|
|
||||||
friend inline bool operator==(
|
friend inline bool operator==(
|
||||||
DescriptorSetLayoutBinding const& lhs,
|
DescriptorSetLayoutBinding const& lhs,
|
||||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||||
return lhs.type == rhs.type &&
|
return lhs.type == rhs.type &&
|
||||||
lhs.flags == rhs.flags &&
|
lhs.flags == rhs.flags &&
|
||||||
lhs.count == rhs.count &&
|
lhs.count == rhs.count &&
|
||||||
lhs.stageFlags == rhs.stageFlags &&
|
lhs.stageFlags == rhs.stageFlags;
|
||||||
lhs.externalSamplerDataIndex == rhs.externalSamplerDataIndex;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DescriptorSetLayout {
|
||||||
|
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bitmask for selecting render buffers
|
* Bitmask for selecting render buffers
|
||||||
*/
|
*/
|
||||||
@@ -970,28 +968,8 @@ enum class SamplerCompareFunc : uint8_t {
|
|||||||
N //!< Never. The depth / stencil test always fails.
|
N //!< Never. The depth / stencil test always fails.
|
||||||
};
|
};
|
||||||
|
|
||||||
//! this API is copied from (and only applies to) the Vulkan spec.
|
|
||||||
//! These specify YUV to RGB conversions.
|
|
||||||
enum class SamplerYcbcrModelConversion : uint8_t {
|
|
||||||
RGB_IDENTITY = 0,
|
|
||||||
YCBCR_IDENTITY = 1,
|
|
||||||
YCBCR_709 = 2,
|
|
||||||
YCBCR_601 = 3,
|
|
||||||
YCBCR_2020 = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SamplerYcbcrRange : uint8_t {
|
|
||||||
ITU_FULL = 0,
|
|
||||||
ITU_NARROW = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ChromaLocation : uint8_t {
|
|
||||||
COSITED_EVEN = 0,
|
|
||||||
MIDPOINT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Sampler parameters
|
//! Sampler parameters
|
||||||
struct SamplerParams { // NOLINT
|
struct SamplerParams { // NOLINT
|
||||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||||
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
|
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
|
||||||
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
|
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||||
@@ -1046,7 +1024,6 @@ private:
|
|||||||
return SamplerParams::LessThan{}(lhs, rhs);
|
return SamplerParams::LessThan{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(SamplerParams) == 4);
|
static_assert(sizeof(SamplerParams) == 4);
|
||||||
|
|
||||||
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
// The limitation to 64-bits max comes from how we store a SamplerParams in our JNI code
|
||||||
@@ -1054,93 +1031,6 @@ static_assert(sizeof(SamplerParams) == 4);
|
|||||||
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
static_assert(sizeof(SamplerParams) <= sizeof(uint64_t),
|
||||||
"SamplerParams must be no more than 64 bits");
|
"SamplerParams must be no more than 64 bits");
|
||||||
|
|
||||||
//! Sampler parameters
|
|
||||||
struct SamplerYcbcrConversion {// NOLINT
|
|
||||||
SamplerYcbcrModelConversion ycbcrModel : 4;
|
|
||||||
TextureSwizzle r : 4;
|
|
||||||
TextureSwizzle g : 4;
|
|
||||||
TextureSwizzle b : 4;
|
|
||||||
TextureSwizzle a : 4;
|
|
||||||
SamplerYcbcrRange ycbcrRange : 1;
|
|
||||||
ChromaLocation xChromaOffset : 1;
|
|
||||||
ChromaLocation yChromaOffset : 1;
|
|
||||||
SamplerMagFilter chromaFilter : 1;
|
|
||||||
uint8_t padding;
|
|
||||||
|
|
||||||
struct Hasher {
|
|
||||||
size_t operator()(const SamplerYcbcrConversion p) const noexcept {
|
|
||||||
// we don't use std::hash<> here, so we don't have to include <functional>
|
|
||||||
return *reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&p));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EqualTo {
|
|
||||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
|
||||||
assert_invariant(lhs.padding == 0);
|
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
|
||||||
return *pLhs == *pRhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LessThan {
|
|
||||||
bool operator()(SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs) const noexcept {
|
|
||||||
assert_invariant(lhs.padding == 0);
|
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
|
||||||
return *pLhs < *pRhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
|
||||||
noexcept {
|
|
||||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(SamplerYcbcrConversion) == 4);
|
|
||||||
|
|
||||||
static_assert(sizeof(SamplerYcbcrConversion) <= sizeof(uint64_t),
|
|
||||||
"SamplerYcbcrConversion must be no more than 64 bits");
|
|
||||||
|
|
||||||
struct ExternalSamplerDatum {
|
|
||||||
ExternalSamplerDatum(SamplerYcbcrConversion ycbcr, SamplerParams spm, uint32_t extFmt)
|
|
||||||
: YcbcrConversion(ycbcr),
|
|
||||||
samplerParams(spm),
|
|
||||||
externalFormat(extFmt) {}
|
|
||||||
bool operator==(ExternalSamplerDatum const& rhs) const {
|
|
||||||
return (YcbcrConversion == rhs.YcbcrConversion && samplerParams == rhs.samplerParams &&
|
|
||||||
externalFormat == rhs.externalFormat);
|
|
||||||
}
|
|
||||||
struct EqualTo {
|
|
||||||
bool operator()(const ExternalSamplerDatum& lhs,
|
|
||||||
const ExternalSamplerDatum& rhs) const noexcept {
|
|
||||||
return (lhs.YcbcrConversion == rhs.YcbcrConversion &&
|
|
||||||
lhs.samplerParams == rhs.samplerParams &&
|
|
||||||
lhs.externalFormat == rhs.externalFormat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SamplerYcbcrConversion YcbcrConversion;
|
|
||||||
SamplerParams samplerParams;
|
|
||||||
uint32_t externalFormat;
|
|
||||||
};
|
|
||||||
// No implicit padding allowed due to it being a hash key.
|
|
||||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
|
||||||
|
|
||||||
struct DescriptorSetLayout {
|
|
||||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
|
||||||
utils::FixedCapacityVector<ExternalSamplerDatum> externalSamplerData;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! blending equation function
|
//! blending equation function
|
||||||
enum class BlendEquation : uint8_t {
|
enum class BlendEquation : uint8_t {
|
||||||
ADD, //!< the fragment is added to the color buffer
|
ADD, //!< the fragment is added to the color buffer
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
PlatformCocoaGL();
|
PlatformCocoaGL();
|
||||||
~PlatformCocoaGL() noexcept override;
|
~PlatformCocoaGL() noexcept override;
|
||||||
|
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
PlatformCocoaTouchGL();
|
PlatformCocoaTouchGL();
|
||||||
~PlatformCocoaTouchGL() noexcept override;
|
~PlatformCocoaTouchGL() noexcept override;
|
||||||
|
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(void* cvPixelBuffer) noexcept;
|
ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Platform Interface
|
// Platform Interface
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Creates an ExternalImage from a EGLImageKHR
|
* Creates an ExternalImage from a EGLImageKHR
|
||||||
*/
|
*/
|
||||||
ExternalImageHandle UTILS_PUBLIC createExternalImage(EGLImageKHR eglImage) noexcept;
|
ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <backend/platforms/PlatformEGL.h>
|
#include <backend/platforms/PlatformEGL.h>
|
||||||
|
|
||||||
#include <utils/android/PerformanceHintManager.h>
|
#include <utils/android/PerformanceHintManager.h>
|
||||||
#include <utils/compiler.h>
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@@ -44,21 +43,8 @@ public:
|
|||||||
PlatformEGLAndroid() noexcept;
|
PlatformEGLAndroid() noexcept;
|
||||||
~PlatformEGLAndroid() noexcept override;
|
~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:
|
protected:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Platform Interface
|
// Platform Interface
|
||||||
|
|
||||||
@@ -71,6 +57,11 @@ protected:
|
|||||||
Driver* createDriver(void* sharedContext,
|
Driver* createDriver(void* sharedContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ExternalImage from a EGLImageKHR
|
||||||
|
*/
|
||||||
|
ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// OpenGLPlatform Interface
|
// OpenGLPlatform Interface
|
||||||
|
|
||||||
@@ -104,26 +95,15 @@ protected:
|
|||||||
*/
|
*/
|
||||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override;
|
||||||
|
|
||||||
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
|
bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override;
|
||||||
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
|
|
||||||
|
|
||||||
struct ExternalImageEGLAndroid : public ExternalImageEGL {
|
struct ExternalImageEGLAndroid : public ExternalImageEGL {
|
||||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
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;
|
bool sRGB = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ExternalImageEGLAndroid() override;
|
~ExternalImageEGLAndroid() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool setExternalImage(ExternalImageHandleRef externalImage,
|
|
||||||
ExternalTexture* texture) noexcept override;
|
|
||||||
bool setImage(ExternalImageEGLAndroid const* eglExternalImage,
|
|
||||||
ExternalTexture* texture) noexcept;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool makeCurrent(ContextType type,
|
bool makeCurrent(ContextType type,
|
||||||
SwapChain* drawSwapChain,
|
SwapChain* drawSwapChain,
|
||||||
|
|||||||
@@ -21,12 +21,7 @@
|
|||||||
|
|
||||||
#include "bluegl/BlueGL.h"
|
#include "bluegl/BlueGL.h"
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <osmesa.h>
|
#include <osmesa.h>
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#undef GLAPI
|
|
||||||
#include <GL/osmesa.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <backend/platforms/OpenGLPlatform.h>
|
#include <backend/platforms/OpenGLPlatform.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -318,11 +317,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32_t layers;
|
uint32_t layers;
|
||||||
|
|
||||||
/**
|
|
||||||
* The numbers of samples per texel
|
|
||||||
*/
|
|
||||||
VkSampleCountFlagBits samples;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The format of the external image
|
* The format of the external image
|
||||||
*/
|
*/
|
||||||
@@ -357,44 +351,20 @@ public:
|
|||||||
|
|
||||||
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||||
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
const ExternalImageMetadata& metadata);
|
||||||
VkImageUsageFlags usage);
|
|
||||||
|
|
||||||
virtual VkSampler createExternalSampler(SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler,
|
|
||||||
uint32_t internalFormat);
|
|
||||||
|
|
||||||
virtual VkImageView createExternalImageView(SamplerYcbcrConversion chroma,
|
|
||||||
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:
|
private:
|
||||||
// Platform dependent helper methods
|
static ExtensionSet getSwapchainInstanceExtensions();
|
||||||
static ExtensionSet getSwapchainInstanceExtensionsImpl();
|
|
||||||
|
|
||||||
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||||
VkDevice device);
|
VkDevice device);
|
||||||
|
|
||||||
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
||||||
VkDevice device, const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex,
|
VkDevice device, const ExternalImageMetadata& metadata);
|
||||||
VkImageUsageFlags usage);
|
|
||||||
static VkSampler createExternalSamplerImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, SamplerParams sampler,
|
|
||||||
uint32_t internalFormat);
|
|
||||||
static VkImageView createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType,
|
|
||||||
VkComponentMapping swizzle);
|
|
||||||
|
|
||||||
// Platform dependent helper methods
|
// 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;
|
uint64_t flags) noexcept;
|
||||||
|
|
||||||
friend struct VulkanPlatformPrivate;
|
friend struct VulkanPlatformPrivate;
|
||||||
|
|||||||
@@ -17,55 +17,27 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
#ifndef TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/platforms/VulkanPlatform.h>
|
|
||||||
|
|
||||||
#include <android/hardware_buffer.h>
|
#include <android/hardware_buffer.h>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend::fvkandroid {
|
||||||
|
|
||||||
class VulkanPlatformAndroid : public VulkanPlatform {
|
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
||||||
public:
|
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||||
Platform::ExternalImageHandle UTILS_PUBLIC createExternalImage(AHardwareBuffer const* buffer,
|
bool sRGB = false;
|
||||||
bool sRGB) noexcept;
|
unsigned int width; // Texture width
|
||||||
|
unsigned int height; // Texture height
|
||||||
struct UTILS_PUBLIC ExternalImageDescAndroid {
|
TextureFormat format; // Texture format
|
||||||
uint32_t width; // Texture width
|
TextureUsage usage; // Texture usage flags
|
||||||
uint32_t height; // Texture height
|
|
||||||
TextureFormat format;// Texture format
|
|
||||||
TextureUsage usage; // Texture usage flags
|
|
||||||
};
|
|
||||||
|
|
||||||
ExternalImageDescAndroid UTILS_PUBLIC getExternalImageDesc(
|
|
||||||
ExternalImageHandleRef externalImage) const noexcept;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
~ExternalImageVulkanAndroid() override;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}// 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
|
||||||
|
|||||||
@@ -1,59 +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_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
|
|
||||||
#include <backend/Platform.h>
|
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Platform interface, handling the environment-specific concerns, e.g. OS, for creating a WebGPU
|
|
||||||
* driver (backend).
|
|
||||||
*/
|
|
||||||
class WebGPUPlatform final : public Platform {
|
|
||||||
public:
|
|
||||||
WebGPUPlatform();
|
|
||||||
~WebGPUPlatform() override = default;
|
|
||||||
|
|
||||||
[[nodiscard]] int getOSVersion() const noexcept final { return 0; }
|
|
||||||
|
|
||||||
[[nodiscard]] wgpu::Instance& getInstance() noexcept { return mInstance; }
|
|
||||||
|
|
||||||
// either returns a valid surface or panics
|
|
||||||
[[nodiscard]] wgpu::Surface createSurface(void* nativeWindow, uint64_t flags);
|
|
||||||
// either returns a valid adapter or panics
|
|
||||||
[[nodiscard]] wgpu::Adapter requestAdapter(wgpu::Surface const& surface);
|
|
||||||
// either returns a valid device or panics
|
|
||||||
[[nodiscard]] wgpu::Device requestDevice(wgpu::Adapter const& adapter);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] Driver* createDriver(void* sharedContext,
|
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// we may consider having the driver own this in the future
|
|
||||||
wgpu::Instance mInstance;
|
|
||||||
};
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_PLATFORMS_WEBGPUPLATFORM_H
|
|
||||||
@@ -362,8 +362,6 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
|
|||||||
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(size_t, getMaxTextureSize, backend::SamplerType, target)
|
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxArrayTextureLayers)
|
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
|
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
|
||||||
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
|
||||||
|
|||||||
@@ -19,11 +19,6 @@
|
|||||||
#include <utils/Systrace.h>
|
#include <utils/Systrace.h>
|
||||||
#include <utils/debug.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__)
|
#if defined(__ANDROID__)
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
@@ -35,11 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
#include <backend/platforms/PlatformCocoaGL.h>
|
||||||
#include <backend/platforms/PlatformOSMesa.h>
|
|
||||||
#else
|
|
||||||
#include <backend/platforms/PlatformCocoaGL.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#if defined(FILAMENT_SUPPORTS_X11)
|
#if defined(FILAMENT_SUPPORTS_X11)
|
||||||
@@ -64,11 +55,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||||
#if defined(__ANDROID__)
|
#include "backend/platforms/VulkanPlatform.h"
|
||||||
#include "backend/platforms/VulkanPlatformAndroid.h"
|
|
||||||
#else
|
|
||||||
#include "backend/platforms/VulkanPlatform.h"
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (FILAMENT_SUPPORTS_METAL)
|
#if defined (FILAMENT_SUPPORTS_METAL)
|
||||||
@@ -78,6 +65,9 @@ filament::backend::Platform* createDefaultMetalPlatform();
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "noop/PlatformNoop.h"
|
#include "noop/PlatformNoop.h"
|
||||||
|
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||||
|
#include "webgpu/WebGPUPlatform.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -114,11 +104,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
|||||||
}
|
}
|
||||||
if (*backend == Backend::VULKAN) {
|
if (*backend == Backend::VULKAN) {
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||||
#if defined(__ANDROID__)
|
return new VulkanPlatform();
|
||||||
return new VulkanPlatformAndroid();
|
|
||||||
#else
|
|
||||||
return new VulkanPlatform();
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
@@ -146,11 +132,7 @@ Platform* PlatformFactory::create(Backend* backend) noexcept {
|
|||||||
#elif defined(FILAMENT_IOS)
|
#elif defined(FILAMENT_IOS)
|
||||||
return new PlatformCocoaTouchGL();
|
return new PlatformCocoaTouchGL();
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#if defined(FILAMENT_SUPPORTS_OSMESA)
|
return new PlatformCocoaGL();
|
||||||
return new PlatformOSMesa();
|
|
||||||
#else
|
|
||||||
return new PlatformCocoaGL();
|
|
||||||
#endif
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#if defined(FILAMENT_SUPPORTS_X11)
|
#if defined(FILAMENT_SUPPORTS_X11)
|
||||||
return new PlatformGLX();
|
return new PlatformGLX();
|
||||||
|
|||||||
@@ -1177,16 +1177,6 @@ size_t MetalDriver::getMaxUniformBufferSize() {
|
|||||||
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
return 256 * 1024 * 1024; // TODO: return the actual size instead of hardcoding the minspec
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MetalDriver::getMaxTextureSize(SamplerType) {
|
|
||||||
// TODO: return the actual size instead of hardcoding the minspec
|
|
||||||
return 2048;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t MetalDriver::getMaxArrayTextureLayers() {
|
|
||||||
// TODO: return the actual size instead of hardcoding the minspec
|
|
||||||
return 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
FILAMENT_CHECK_PRECONDITION(data.buffer)
|
FILAMENT_CHECK_PRECONDITION(data.buffer)
|
||||||
|
|||||||
@@ -240,14 +240,6 @@ size_t NoopDriver::getMaxUniformBufferSize() {
|
|||||||
return 16384u;
|
return 16384u;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NoopDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
return 2048u;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t NoopDriver::getMaxArrayTextureLayers() {
|
|
||||||
return 256u;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
namespace filament::backend {
|
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();
|
return NoopDriver::create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,22 +94,18 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initExtensions(&ext, state.major, state.minor);
|
OpenGLContext::initExtensions(&ext, state.major, state.minor);
|
||||||
|
|
||||||
initProcs(&procs, ext, state.major, state.minor);
|
OpenGLContext::initProcs(&procs, ext, state.major, state.minor);
|
||||||
|
|
||||||
initBugs(&bugs, ext, state.major, state.minor,
|
OpenGLContext::initBugs(&bugs, ext, state.major, state.minor,
|
||||||
state.vendor, state.renderer, state.version, state.shader);
|
state.vendor, state.renderer, state.version, state.shader);
|
||||||
|
|
||||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
|
||||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gets.max_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gets.max_cubemap_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gets.max_3d_texture_size);
|
|
||||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gets.max_array_texture_layers);
|
|
||||||
|
|
||||||
mFeatureLevel = resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
mFeatureLevel = OpenGLContext::resolveFeatureLevel(state.major, state.minor, ext, gets, bugs);
|
||||||
|
|
||||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||||
mShaderModel = ShaderModel::MOBILE;
|
mShaderModel = ShaderModel::MOBILE;
|
||||||
@@ -181,14 +177,6 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
|||||||
<< gets.max_anisotropy << '\n'
|
<< gets.max_anisotropy << '\n'
|
||||||
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
||||||
<< gets.max_combined_texture_image_units << '\n'
|
<< gets.max_combined_texture_image_units << '\n'
|
||||||
<< "GL_MAX_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_texture_size << '\n'
|
|
||||||
<< "GL_MAX_CUBE_MAP_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_cubemap_texture_size << '\n'
|
|
||||||
<< "GL_MAX_3D_TEXTURE_SIZE = "
|
|
||||||
<< gets.max_3d_texture_size << '\n'
|
|
||||||
<< "GL_MAX_ARRAY_TEXTURE_LAYERS = "
|
|
||||||
<< gets.max_array_texture_layers << '\n'
|
|
||||||
<< "GL_MAX_DRAW_BUFFERS = "
|
<< "GL_MAX_DRAW_BUFFERS = "
|
||||||
<< gets.max_draw_buffers << '\n'
|
<< gets.max_draw_buffers << '\n'
|
||||||
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
||||||
|
|||||||
@@ -203,10 +203,6 @@ public:
|
|||||||
GLint max_renderbuffer_size;
|
GLint max_renderbuffer_size;
|
||||||
GLint max_samples;
|
GLint max_samples;
|
||||||
GLint max_texture_image_units;
|
GLint max_texture_image_units;
|
||||||
GLint max_texture_size;
|
|
||||||
GLint max_cubemap_texture_size;
|
|
||||||
GLint max_3d_texture_size;
|
|
||||||
GLint max_array_texture_layers;
|
|
||||||
GLint max_transform_feedback_separate_attribs;
|
GLint max_transform_feedback_separate_attribs;
|
||||||
GLint max_uniform_block_size;
|
GLint max_uniform_block_size;
|
||||||
GLint max_uniform_buffer_bindings;
|
GLint max_uniform_buffer_bindings;
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ using namespace utils;
|
|||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
Driver* OpenGLDriverFactory::create(
|
Driver* OpenGLDriverFactory::create(
|
||||||
OpenGLPlatform* platform,
|
OpenGLPlatform* const platform,
|
||||||
void* sharedGLContext,
|
void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
return OpenGLDriver::create(platform, sharedGLContext, driverConfig);
|
return OpenGLDriver::create(platform, sharedGLContext, driverConfig);
|
||||||
}
|
}
|
||||||
@@ -159,10 +159,10 @@ using namespace GLUtils;
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
|
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
||||||
void* /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
assert_invariant(platform);
|
assert_invariant(platform);
|
||||||
OpenGLPlatform* ec = platform;
|
OpenGLPlatform* const ec = platform;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// this is useful for development, but too verbose even for debug builds
|
// 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;
|
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||||
Platform::DriverConfig validConfig{ driverConfig };
|
Platform::DriverConfig validConfig{ driverConfig };
|
||||||
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
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;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2460,26 +2460,6 @@ size_t OpenGLDriver::getMaxUniformBufferSize() {
|
|||||||
return mContext.gets.max_uniform_block_size;
|
return mContext.gets.max_uniform_block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OpenGLDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
switch (target) {
|
|
||||||
case SamplerType::SAMPLER_2D:
|
|
||||||
case SamplerType::SAMPLER_2D_ARRAY:
|
|
||||||
case SamplerType::SAMPLER_EXTERNAL:
|
|
||||||
return mContext.gets.max_texture_size;
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
|
||||||
return mContext.gets.max_cubemap_texture_size;
|
|
||||||
case SamplerType::SAMPLER_3D:
|
|
||||||
return mContext.gets.max_3d_texture_size;
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
|
||||||
return mContext.gets.max_cubemap_texture_size;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t OpenGLDriver::getMaxArrayTextureLayers() {
|
|
||||||
return mContext.gets.max_array_texture_layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Swap chains
|
// Swap chains
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ PlatformCocoaTouchGL::~PlatformCocoaTouchGL() noexcept {
|
|||||||
delete pImpl;
|
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;
|
EAGLSharegroup* sharegroup = (__bridge EAGLSharegroup*) sharedGLContext;
|
||||||
|
|
||||||
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 sharegroup:sharegroup];
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <backend/platforms/PlatformEGL.h>
|
#include <backend/platforms/PlatformEGL.h>
|
||||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
#include <backend/platforms/PlatformEGLAndroid.h>
|
||||||
|
|
||||||
#include <private/backend/BackendUtilsAndroid.h>
|
|
||||||
#include <private/backend/VirtualMachineEnv.h>
|
#include <private/backend/VirtualMachineEnv.h>
|
||||||
|
|
||||||
#include "opengl/GLUtils.h"
|
#include "opengl/GLUtils.h"
|
||||||
@@ -35,8 +34,6 @@
|
|||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/compiler.h>
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
@@ -234,133 +231,26 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
|||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() {
|
PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default;
|
||||||
if (__builtin_available(android 26, *)) {
|
|
||||||
if (aHardwareBuffer) {
|
|
||||||
AHardwareBuffer_release(aHardwareBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer,
|
Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
||||||
bool sRGB) noexcept {
|
auto* const p = new(std::nothrow) ExternalImageEGLAndroid;
|
||||||
if (__builtin_available(android 26, *)) {
|
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
||||||
auto* const p = new (std::nothrow) ExternalImageEGLAndroid;
|
p->sRGB = sRGB;
|
||||||
auto hardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
return ExternalImageHandle{ p };
|
||||||
AHardwareBuffer_acquire(hardwareBuffer);
|
|
||||||
p->aHardwareBuffer = hardwareBuffer;
|
|
||||||
p->sRGB = sRGB;
|
|
||||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
|
||||||
AHardwareBuffer_describe(hardwareBuffer, &hardwareBufferDescription);
|
|
||||||
p->height = hardwareBufferDescription.height;
|
|
||||||
p->width = hardwareBufferDescription.width;
|
|
||||||
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
|
||||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
|
||||||
return ExternalImageHandle{ p };
|
|
||||||
}
|
|
||||||
|
|
||||||
return Platform::ExternalImageHandle{};
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformEGLAndroid::ExternalImageDescAndroid PlatformEGLAndroid::getExternalImageDesc(
|
|
||||||
ExternalImageHandle externalImage) noexcept {
|
|
||||||
auto const* const eglExternalImage =
|
|
||||||
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
|
||||||
ExternalImageDescAndroid metadata = {};
|
|
||||||
if (!eglExternalImage) {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
metadata.height = eglExternalImage->height;
|
|
||||||
metadata.width = eglExternalImage->width;
|
|
||||||
metadata.format = eglExternalImage->format;
|
|
||||||
metadata.usage = eglExternalImage->usage;
|
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage,
|
bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage,
|
||||||
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept {
|
||||||
auto const* const eglExternalImage =
|
auto const* const eglExternalImage = static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
||||||
static_cast<ExternalImageEGLAndroid const*>(externalImage.get());
|
|
||||||
if (eglExternalImage->aHardwareBuffer) {
|
if (eglExternalImage->aHardwareBuffer) {
|
||||||
return PlatformEGLAndroid::setImage(eglExternalImage, texture);
|
// TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// not a AHardwareBuffer, fallback to the inherited version
|
// not a AHardwareBuffer, fallback to the inherited version
|
||||||
return PlatformEGL::setExternalImage(externalImage, texture);
|
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 {
|
void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept {
|
||||||
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
|
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
|
||||||
if (currentDrawSurface != EGL_NO_SURFACE) {
|
if (currentDrawSurface != EGL_NO_SURFACE) {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
Driver* PlatformGLX::createDriver(void* sharedGLContext,
|
Driver* PlatformGLX::createDriver(void* const sharedGLContext,
|
||||||
const DriverConfig& driverConfig) noexcept {
|
const DriverConfig& driverConfig) noexcept {
|
||||||
loadLibraries();
|
loadLibraries();
|
||||||
// Get the display device
|
// Get the display device
|
||||||
|
|||||||
@@ -22,11 +22,9 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
// This is to ensure that linking during compilation will not fail even if
|
// This is to ensure that linking during compilation will not fail even if
|
||||||
// OSMesaGetProcAddress is not linked.
|
// OSMesaGetProcAddress is not linked.
|
||||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -50,27 +48,20 @@ struct OSMesaSwapchain {
|
|||||||
|
|
||||||
struct OSMesaAPI {
|
struct OSMesaAPI {
|
||||||
private:
|
private:
|
||||||
using CreateContextAttribsFunc = OSMesaContext (*)(const int *, OSMesaContext);
|
using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext);
|
||||||
using DestroyContextFunc = GLboolean (*)(OSMesaContext);
|
using DestroyContextFunc = GLboolean (*)(OSMesaContext);
|
||||||
using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type,
|
using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type,
|
||||||
GLsizei width, GLsizei height);
|
GLsizei width, GLsizei height);
|
||||||
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CreateContextAttribsFunc fOSMesaCreateContextAttribs;
|
CreateContextFunc fOSMesaCreateContext;
|
||||||
DestroyContextFunc fOSMesaDestroyContext;
|
DestroyContextFunc fOSMesaDestroyContext;
|
||||||
MakeCurrentFunc fOSMesaMakeCurrent;
|
MakeCurrentFunc fOSMesaMakeCurrent;
|
||||||
GetProcAddressFunc fOSMesaGetProcAddress;
|
GetProcAddressFunc fOSMesaGetProcAddress;
|
||||||
|
|
||||||
OSMesaAPI() {
|
OSMesaAPI() {
|
||||||
static constexpr char const* libraryNames[] = {
|
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||||
#if defined(__linux__)
|
|
||||||
"libOSMesa.so",
|
|
||||||
"libosmesa.so",
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
"libOSMesa.dylib",
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
for (char const* libName: libraryNames) {
|
for (char const* libName: libraryNames) {
|
||||||
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
|
mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW);
|
||||||
if (mLib) {
|
if (mLib) {
|
||||||
@@ -80,24 +71,22 @@ public:
|
|||||||
if (mLib) {
|
if (mLib) {
|
||||||
// Loading from a libosmesa.os
|
// Loading from a libosmesa.os
|
||||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||||
}
|
} else {
|
||||||
#if defined(__linux__)
|
|
||||||
else {
|
|
||||||
// Filament is built into a .so
|
// Filament is built into a .so
|
||||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fOSMesaGetProcAddress) {
|
if (!fOSMesaGetProcAddress) {
|
||||||
// Statically linking osmesa
|
// Statically linking osmesa
|
||||||
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
||||||
}
|
}
|
||||||
#endif // __linux__
|
|
||||||
|
|
||||||
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
||||||
<< "Unable to link against libOSMesa to create a software GL context";
|
<< "Unable to link against libOSMesa to create a software GL context";
|
||||||
|
|
||||||
fOSMesaCreateContextAttribs =
|
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
|
||||||
(CreateContextAttribsFunc) fOSMesaGetProcAddress("OSMesaCreateContextAttribs");
|
fOSMesaDestroyContext =
|
||||||
fOSMesaDestroyContext = (DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||||
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,24 +101,14 @@ private:
|
|||||||
|
|
||||||
}// anonymous namespace
|
}// anonymous namespace
|
||||||
|
|
||||||
Driver* PlatformOSMesa::createDriver(void* sharedGLContext,
|
Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||||
const DriverConfig& driverConfig) noexcept {
|
const DriverConfig& driverConfig) noexcept {
|
||||||
|
|
||||||
OSMesaAPI* api = new OSMesaAPI();
|
OSMesaAPI* api = new OSMesaAPI();
|
||||||
mOsMesaApi = api;
|
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)
|
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
|
||||||
<< "shared GL context is not supported with PlatformOSMesa";
|
<< "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
|
// We need to do a no-op makecurrent here so that the context will be in a correct state before
|
||||||
// any GL calls.
|
// any GL calls.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ struct WGLSwapChain {
|
|||||||
|
|
||||||
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
|
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
|
||||||
|
|
||||||
Driver* PlatformWGL::createDriver(void* sharedGLContext,
|
Driver* PlatformWGL::createDriver(void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int pixelFormat = 0;
|
int pixelFormat = 0;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace filament::backend {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
Driver* PlatformWebGL::createDriver(void* sharedGLContext,
|
Driver* PlatformWebGL::createDriver(void* const sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept {
|
const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
return OpenGLPlatform::createDefaultDriver(this, sharedGLContext, driverConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG | FVK_DEBUG_VALIDATION)
|
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG)
|
||||||
#else
|
#else
|
||||||
#define FVK_DEBUG_FLAGS 0
|
#define FVK_DEBUG_FLAGS 0
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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 "VulkanDriver.h"
|
||||||
|
|
||||||
#include "CommandStreamDispatcher.h"
|
#include "CommandStreamDispatcher.h"
|
||||||
|
#include "DataReshaper.h"
|
||||||
#include "SystraceProfile.h"
|
#include "SystraceProfile.h"
|
||||||
#include "VulkanAsyncHandles.h"
|
#include "VulkanAsyncHandles.h"
|
||||||
#include "VulkanBuffer.h"
|
#include "VulkanBuffer.h"
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
#include <backend/platforms/VulkanPlatform.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@@ -42,6 +44,8 @@
|
|||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
|
using utils::FixedCapacityVector;
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
||||||
// to a stack-allocated variable.
|
// to a stack-allocated variable.
|
||||||
@@ -215,8 +219,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
|
|||||||
mSamplerCache(mPlatform->getDevice()),
|
mSamplerCache(mPlatform->getDevice()),
|
||||||
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
||||||
mReadPixels(mPlatform->getDevice()),
|
mReadPixels(mPlatform->getDevice()),
|
||||||
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager),
|
||||||
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
|
||||||
mQueryManager(mPlatform->getDevice()),
|
mQueryManager(mPlatform->getDevice()),
|
||||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||||
mStereoscopicType(driverConfig.stereoscopicType) {
|
mStereoscopicType(driverConfig.stereoscopicType) {
|
||||||
@@ -326,8 +329,7 @@ void VulkanDriver::terminate() {
|
|||||||
mPipelineCache.terminate();
|
mPipelineCache.terminate();
|
||||||
mFramebufferCache.reset();
|
mFramebufferCache.reset();
|
||||||
mSamplerCache.terminate();
|
mSamplerCache.terminate();
|
||||||
mDescriptorSetLayoutCache.terminate();
|
mDescriptorSetManager.terminate();
|
||||||
mDescriptorSetCache.terminate();
|
|
||||||
mPipelineLayoutCache.terminate();
|
mPipelineLayoutCache.terminate();
|
||||||
|
|
||||||
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
|
// 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();
|
FVK_SYSTRACE_SCOPE();
|
||||||
// Command buffers need to be submitted and completed before other resources can be gc'd.
|
// Command buffers need to be submitted and completed before other resources can be gc'd.
|
||||||
mCommands.gc();
|
mCommands.gc();
|
||||||
mDescriptorSetCache.clearHistory();
|
mDescriptorSetManager.clearHistory();
|
||||||
mStagePool.gc();
|
mStagePool.gc();
|
||||||
mFramebufferCache.gc();
|
mFramebufferCache.gc();
|
||||||
mPipelineCache.gc();
|
mPipelineCache.gc();
|
||||||
@@ -406,7 +408,7 @@ void VulkanDriver::updateDescriptorSetBuffer(
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
auto buffer = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
|
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(
|
void VulkanDriver::updateDescriptorSetTexture(
|
||||||
@@ -419,7 +421,7 @@ void VulkanDriver::updateDescriptorSetTexture(
|
|||||||
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
auto texture = resource_ptr<VulkanTexture>::cast(&mResourceManager, th);
|
||||||
|
|
||||||
VkSampler const vksampler = mSamplerCache.getSampler(params);
|
VkSampler const vksampler = mSamplerCache.getSampler(params);
|
||||||
mDescriptorSetCache.updateSampler(set, binding, texture, vksampler);
|
mDescriptorSetManager.updateSampler(set, binding, texture, vksampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::flush(int) {
|
void VulkanDriver::flush(int) {
|
||||||
@@ -552,43 +554,26 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
|||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::SamplerType target, backend::TextureFormat format,
|
||||||
|
uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
Platform::ExternalImageHandleRef externalImage) {
|
Platform::ExternalImageHandleRef externalImage) {
|
||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
|
|
||||||
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||||
if (metadata.isProtected) {
|
if (metadata.isProtected) {
|
||||||
usage |= backend::TextureUsage::PROTECTED;
|
usage |= backend::TextureUsage::PROTECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageUsageFlags vkUsage = metadata.usage;
|
|
||||||
if (any(usage & TextureUsage::BLIT_SRC)) {
|
|
||||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (any(usage & (TextureUsage::BLIT_DST & TextureUsage::UPLOADABLE))) {
|
|
||||||
vkUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_invariant(width == metadata.width);
|
assert_invariant(width == metadata.width);
|
||||||
assert_invariant(height == metadata.height);
|
assert_invariant(height == metadata.height);
|
||||||
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||||
|
|
||||||
VkMemoryPropertyFlags const requiredMemoryFlags = any(usage & TextureUsage::UPLOADABLE)
|
const auto& data = mPlatform->createExternalImageData(externalImage, metadata);
|
||||||
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
||||||
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
uint32_t const memoryTypeIndex =
|
|
||||||
mContext.selectMemoryType(metadata.memoryTypeBits, requiredMemoryFlags);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex != VK_MAX_MEMORY_TYPES)
|
|
||||||
<< "failed to find a valid memory type for external image memory.";
|
|
||||||
|
|
||||||
const auto& data =
|
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th,
|
||||||
mPlatform->createExternalImageData(externalImage, metadata, memoryTypeIndex, vkUsage);
|
mPlatform->getDevice(), mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||||
|
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
|
||||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
|
||||||
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
|
||||||
metadata.samples, metadata.width, metadata.height, metadata.layerCount, usage,
|
|
||||||
mStagePool);
|
|
||||||
|
|
||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
@@ -776,7 +761,8 @@ void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
|||||||
|
|
||||||
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
||||||
backend::DescriptorSetLayout&& info) {
|
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();
|
layout.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,7 +771,7 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
|
||||||
auto set = mDescriptorSetCache.createSet(dsh, layout);
|
auto set = mDescriptorSetManager.createSet(dsh, layout);
|
||||||
set.inc();
|
set.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,16 +1130,6 @@ size_t VulkanDriver::getMaxUniformBufferSize() {
|
|||||||
return 32768;
|
return 32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VulkanDriver::getMaxTextureSize(SamplerType) {
|
|
||||||
// TODO: return the actual size instead of hardcoded value
|
|
||||||
return 2048;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t VulkanDriver::getMaxArrayTextureLayers() {
|
|
||||||
// TODO: return the actual size instead of hardcoded value
|
|
||||||
return 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
||||||
Handle<HwBufferObject> boh) {
|
Handle<HwBufferObject> boh) {
|
||||||
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
|
||||||
@@ -1490,7 +1466,7 @@ void VulkanDriver::nextSubpass(int) {
|
|||||||
|
|
||||||
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
||||||
VulkanAttachment& subpassInput = renderTarget->getColor0();
|
VulkanAttachment& subpassInput = renderTarget->getColor0();
|
||||||
mDescriptorSetCache.updateInputAttachment({}, subpassInput);
|
mDescriptorSetManager.updateInputAttachment({}, subpassInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1817,9 +1793,9 @@ void VulkanDriver::bindDescriptorSet(
|
|||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
if (dsh) {
|
if (dsh) {
|
||||||
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
auto set = resource_ptr<VulkanDescriptorSet>::cast(&mResourceManager, dsh);
|
||||||
mDescriptorSetCache.bind(setIndex, set, std::move(offsets));
|
mDescriptorSetManager.bind(setIndex, set, std::move(offsets));
|
||||||
} else {
|
} else {
|
||||||
mDescriptorSetCache.unbind(setIndex);
|
mDescriptorSetManager.unbind(setIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1827,7 +1803,7 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
|
|||||||
FVK_SYSTRACE_SCOPE();
|
FVK_SYSTRACE_SCOPE();
|
||||||
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer();
|
||||||
|
|
||||||
mDescriptorSetCache.commit(mCurrentRenderPass.commandBuffer,
|
mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer,
|
||||||
mBoundPipeline.pipelineLayout,
|
mBoundPipeline.pipelineLayout,
|
||||||
mBoundPipeline.descriptorSetMask);
|
mBoundPipeline.descriptorSetMask);
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,8 @@
|
|||||||
#include "VulkanSamplerCache.h"
|
#include "VulkanSamplerCache.h"
|
||||||
#include "VulkanStagePool.h"
|
#include "VulkanStagePool.h"
|
||||||
#include "VulkanQueryManager.h"
|
#include "VulkanQueryManager.h"
|
||||||
#include "vulkan/VulkanDescriptorSetCache.h"
|
#include "vulkan/caching/VulkanDescriptorSetManager.h"
|
||||||
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
|
#include "vulkan/caching/VulkanPipelineLayoutCache.h"
|
||||||
#include "vulkan/VulkanPipelineLayoutCache.h"
|
|
||||||
#include "vulkan/memory/ResourceManager.h"
|
#include "vulkan/memory/ResourceManager.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Definitions.h"
|
#include "vulkan/utils/Definitions.h"
|
||||||
@@ -138,8 +137,7 @@ private:
|
|||||||
VulkanSamplerCache mSamplerCache;
|
VulkanSamplerCache mSamplerCache;
|
||||||
VulkanBlitter mBlitter;
|
VulkanBlitter mBlitter;
|
||||||
VulkanReadPixels mReadPixels;
|
VulkanReadPixels mReadPixels;
|
||||||
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
VulkanDescriptorSetManager mDescriptorSetManager;
|
||||||
VulkanDescriptorSetCache mDescriptorSetCache;
|
|
||||||
VulkanQueryManager mQueryManager;
|
VulkanQueryManager mQueryManager;
|
||||||
|
|
||||||
// This is necessary for us to write to push constants after binding a pipeline.
|
// This is necessary for us to write to push constants after binding a pipeline.
|
||||||
|
|||||||
@@ -15,12 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanPipelineCache.h"
|
#include "VulkanPipelineCache.h"
|
||||||
|
#include "VulkanMemory.h"
|
||||||
|
#include "caching/VulkanDescriptorSetManager.h"
|
||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
#include "VulkanConstants.h"
|
#include "VulkanConstants.h"
|
||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
|
#include "VulkanTexture.h"
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
|
|||||||
@@ -23,6 +23,79 @@ using namespace bluevk;
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
constexpr inline VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) noexcept {
|
||||||
|
switch (mode) {
|
||||||
|
case SamplerWrapMode::REPEAT:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
case SamplerWrapMode::CLAMP_TO_EDGE:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
case SamplerWrapMode::MIRRORED_REPEAT:
|
||||||
|
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkFilter getFilter(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkFilter getFilter(SamplerMagFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMagFilter::NEAREST:
|
||||||
|
return VK_FILTER_NEAREST;
|
||||||
|
case SamplerMagFilter::LINEAR:
|
||||||
|
return VK_FILTER_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline float getMaxLod(SamplerMinFilter filter) noexcept {
|
||||||
|
switch (filter) {
|
||||||
|
case SamplerMinFilter::NEAREST:
|
||||||
|
case SamplerMinFilter::LINEAR:
|
||||||
|
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
||||||
|
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
||||||
|
return 0.25f;
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
||||||
|
return VK_LOD_CLAMP_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept {
|
||||||
|
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
||||||
: mDevice(device) {}
|
: mDevice(device) {}
|
||||||
|
|
||||||
@@ -33,18 +106,18 @@ VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept {
|
|||||||
}
|
}
|
||||||
VkSamplerCreateInfo samplerInfo {
|
VkSamplerCreateInfo samplerInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
.magFilter = fvkutils::getFilter(params.filterMag),
|
.magFilter = getFilter(params.filterMag),
|
||||||
.minFilter = fvkutils::getFilter(params.filterMin),
|
.minFilter = getFilter(params.filterMin),
|
||||||
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
.mipmapMode = getMipmapMode(params.filterMin),
|
||||||
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
.addressModeU = getWrapMode(params.wrapS),
|
||||||
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
.addressModeV = getWrapMode(params.wrapT),
|
||||||
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
.addressModeW = getWrapMode(params.wrapR),
|
||||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
.anisotropyEnable = params.anisotropyLog2 == 0 ? 0u : 1u,
|
||||||
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
||||||
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
.compareEnable = getCompareEnable(params.compareMode),
|
||||||
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
||||||
.minLod = 0.0f,
|
.minLod = 0.0f,
|
||||||
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
.maxLod = getMaxLod(params.filterMin),
|
||||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||||
.unnormalizedCoordinates = VK_FALSE
|
.unnormalizedCoordinates = VK_FALSE
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,61 +55,63 @@ VkComponentMapping composeSwizzle(VkComponentMapping const& prev, VkComponentMap
|
|||||||
VK_COMPONENT_SWIZZLE_A,
|
VK_COMPONENT_SWIZZLE_A,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const compose = [](VkComponentMapping const& prev,
|
auto const compose = [](VkComponentSwizzle out, VkComponentMapping const& prev,
|
||||||
VkComponentMapping const& next) -> VkComponentMapping {
|
uint8_t channelIndex) {
|
||||||
VkComponentSwizzle vals[4] = { next.r, next.g, next.b, next.a };
|
// We need to first change all identities to its equivalent channel.
|
||||||
for (auto& out: vals) {
|
if (out == VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||||
switch (out) {
|
out = IDENTITY[channelIndex];
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 {
|
auto const identityToChannel = [](VkComponentSwizzle val, uint8_t channelIndex) {
|
||||||
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
|
if (val != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
return val;
|
||||||
if (vals[i] != VK_COMPONENT_SWIZZLE_IDENTITY) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vals[i] = IDENTITY[i];
|
|
||||||
}
|
}
|
||||||
return { vals[0], vals[1], vals[2], vals[3] };
|
return IDENTITY[channelIndex];
|
||||||
};
|
|
||||||
auto const channelToIdentity = [](VkComponentMapping const& mapping) -> VkComponentMapping {
|
|
||||||
VkComponentSwizzle vals[4] = { mapping.r, mapping.g, mapping.b, mapping.a };
|
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
|
||||||
if (IDENTITY[i] != vals[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vals[i] = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
||||||
}
|
|
||||||
return { vals[0], vals[1], vals[2], vals[3] };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We make sure all all identities are mapped into respective channels so that actual channel
|
// We make sure all all identities are mapped into respective channels so that actual channel
|
||||||
// mapping will be passed onto the output.
|
// mapping will be passed onto the output.
|
||||||
VkComponentMapping const prevExplicit = identityToChannel(prev);
|
VkComponentMapping const prevExplicit = {
|
||||||
VkComponentMapping const nextExplicit = identityToChannel(next);
|
identityToChannel(prev.r, 0),
|
||||||
return channelToIdentity(compose(prevExplicit, nextExplicit));
|
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) {
|
inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
||||||
@@ -151,6 +153,7 @@ uint8_t getLayerCountFromDepth(uint32_t const depth) {
|
|||||||
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
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.
|
// Determine if we can use the transient usage flag combined with lazily allocated memory.
|
||||||
const bool useTransientAttachment =
|
const bool useTransientAttachment =
|
||||||
// Lazily allocated memory is available.
|
// Lazily allocated memory is available.
|
||||||
context.isLazilyAllocatedMemorySupported() &&
|
context.isLazilyAllocatedMemorySupported() &&
|
||||||
// Usage consists of attachment flags only.
|
// Usage consists of attachment flags only.
|
||||||
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
// Usage contains at least one attachment flag.
|
// Usage contains at least one attachment flag.
|
||||||
any(tusage & TextureUsage::ALL_ATTACHMENTS) &&
|
any(tusage & TextureUsage::ALL_ATTACHMENTS);
|
||||||
// Depth resolve cannot use transient attachment because it uses a custom shader.
|
|
||||||
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
|
|
||||||
// restriction.
|
|
||||||
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
|
|
||||||
// and above to be able to support stencil resolve (along with depth).
|
|
||||||
!(any(usage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
|
|
||||||
|
|
||||||
mState->mIsTransientAttachment = useTransientAttachment;
|
mState->mIsTransientAttachment = useTransientAttachment;
|
||||||
|
|
||||||
const VkImageUsageFlags transientFlag =
|
const VkImageUsageFlags transientFlag =
|
||||||
|
|||||||
@@ -14,25 +14,35 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanDescriptorSetCache.h"
|
#include "VulkanDescriptorSetManager.h"
|
||||||
|
|
||||||
#include "VulkanCommands.h"
|
#include "vulkan/VulkanCommands.h"
|
||||||
#include "VulkanHandles.h"
|
#include "vulkan/VulkanHandles.h"
|
||||||
#include "VulkanConstants.h"
|
#include "vulkan/VulkanConstants.h"
|
||||||
|
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using BitmaskGroup = VulkanDescriptorSetLayout::Bitmask;
|
||||||
using DescriptorCount = VulkanDescriptorSetLayout::Count;
|
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
|
// We create a pool for each layout as defined by the number of descriptors of each type. For
|
||||||
// example, a layout of
|
// 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
|
} // anonymous namespace
|
||||||
|
|
||||||
// This is an ever-expanding pool of sets where it
|
// This is an ever-expanding pool of sets where it
|
||||||
// 1. Keeps a list of smaller pools of different layout-dimensions.
|
// 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.
|
// 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:
|
private:
|
||||||
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
|
static constexpr uint16_t EXPECTED_SET_COUNT = 10;
|
||||||
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
|
static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5;
|
||||||
@@ -249,34 +319,61 @@ private:
|
|||||||
std::vector<std::unique_ptr<DescriptorPool>> mPools;
|
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)
|
fvkmemory::ResourceManager* resourceManager)
|
||||||
: mDevice(device),
|
: mDevice(device),
|
||||||
mResourceManager(resourceManager),
|
mResourceManager(resourceManager),
|
||||||
|
mLayoutManager(std::make_unique<DescriptorSetLayoutManager>(device)),
|
||||||
mDescriptorPool(std::make_unique<DescriptorInfinitePool>(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();
|
mDescriptorPool.reset();
|
||||||
clearHistory();
|
clearHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind() is not really binding the set but just stashing until we have all the info
|
// bind() is not really binding the set but just stashing until we have all the info
|
||||||
// (pipelinelayout).
|
// (pipelinelayout).
|
||||||
void VulkanDescriptorSetCache::bind(uint8_t setIndex,
|
void VulkanDescriptorSetManager::bind(uint8_t setIndex,
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
set->setOffsets(std::move(offsets));
|
set->setOffsets(std::move(offsets));
|
||||||
mStashedSets[setIndex] = set;
|
mStashedSets[setIndex] = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::unbind(uint8_t setIndex) {
|
void VulkanDescriptorSetManager::unbind(uint8_t setIndex) {
|
||||||
mStashedSets[setIndex] = {};
|
mStashedSets[setIndex] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::commit(VulkanCommandBuffer* commands,
|
void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands,
|
||||||
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
|
VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) {
|
||||||
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
// setMask indicates the set of descriptor sets the driver wants to bind, curMask is the
|
||||||
// actual set of sets that *needs* to be bound.
|
// 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,
|
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
|
||||||
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
VkDeviceSize offset, VkDeviceSize size) noexcept {
|
||||||
VkDescriptorBufferInfo const info = {
|
VkDescriptorBufferInfo const info = {
|
||||||
@@ -341,7 +438,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
|
|||||||
set->acquire(bufferObject);
|
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,
|
uint8_t binding, fvkmemory::resource_ptr<VulkanTexture> texture,
|
||||||
VkSampler sampler) noexcept {
|
VkSampler sampler) noexcept {
|
||||||
VkDescriptorImageInfo info{
|
VkDescriptorImageInfo info{
|
||||||
@@ -373,13 +470,13 @@ void VulkanDescriptorSetCache::updateSampler(fvkmemory::resource_ptr<VulkanDescr
|
|||||||
set->acquire(texture);
|
set->acquire(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDescriptorSetCache::updateInputAttachment(
|
void VulkanDescriptorSetManager::updateInputAttachment(
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
fvkmemory::resource_ptr<VulkanDescriptorSet> set,
|
||||||
VulkanAttachment const& attachment) noexcept {
|
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) {
|
Handle<HwDescriptorSet> handle, fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout) {
|
||||||
auto const vkSet = mDescriptorPool->obtainSet(layout);
|
auto const vkSet = mDescriptorPool->obtainSet(layout);
|
||||||
auto const& count = layout->count;
|
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 = {};
|
mStashedSets = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,10 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
#ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
#define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include "vulkan/VulkanHandles.h"
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
|
#include "vulkan/utils/Definitions.h" // For DescriptorSetMask
|
||||||
|
|
||||||
@@ -34,16 +34,20 @@
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
// Abstraction over the descriptor set pool.
|
// [GDSR]: Great-Descriptor-Set-Refactor: As of 03/20/24, the Filament frontend is planning to
|
||||||
class VulkanDescriptorSetCache {
|
// 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:
|
public:
|
||||||
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
|
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
|
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
|
||||||
|
|
||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
||||||
|
|
||||||
VulkanDescriptorSetCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
||||||
~VulkanDescriptorSetCache();
|
~VulkanDescriptorSetManager();
|
||||||
|
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
|
|
||||||
@@ -68,9 +72,12 @@ public:
|
|||||||
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
fvkmemory::resource_ptr<VulkanDescriptorSet> createSet(Handle<HwDescriptorSet> handle,
|
||||||
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
|
void initVkLayout(fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout);
|
||||||
|
|
||||||
void clearHistory();
|
void clearHistory();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class DescriptorSetLayoutManager;
|
||||||
class DescriptorInfinitePool;
|
class DescriptorInfinitePool;
|
||||||
|
|
||||||
using DescriptorSetArray =
|
using DescriptorSetArray =
|
||||||
@@ -78,6 +85,7 @@ private:
|
|||||||
|
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
fvkmemory::ResourceManager* mResourceManager;
|
fvkmemory::ResourceManager* mResourceManager;
|
||||||
|
std::unique_ptr<DescriptorSetLayoutManager> mLayoutManager;
|
||||||
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
|
std::unique_ptr<DescriptorInfinitePool> mDescriptorPool;
|
||||||
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
std::pair<VulkanAttachment, VkDescriptorImageInfo> mInputAttachment;
|
||||||
DescriptorSetArray mStashedSets = {};
|
DescriptorSetArray mStashedSets = {};
|
||||||
@@ -91,4 +99,4 @@ private:
|
|||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETCACHE_H
|
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include <vulkan/VulkanHandles.h>
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
@@ -983,32 +983,10 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
||||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata) {
|
||||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata);
|
||||||
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata, memoryTypeIndex,
|
|
||||||
usage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSampler(SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler, uint32_t internalFormat) {
|
|
||||||
return createExternalSamplerImpl(mImpl->mDevice, chroma, sampler, internalFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageView(SamplerYcbcrConversion chroma,
|
|
||||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
|
||||||
VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
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
|
#undef SWAPCHAIN_RET_FUNC
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -13,16 +13,15 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
#include <backend/platforms/VulkanPlatform.h>
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||||
#include <private/backend/BackendUtilsAndroid.h>
|
#include <private/backend/BackendUtilsAndroid.h>
|
||||||
|
|
||||||
#include "vulkan/VulkanConstants.h"
|
#include "vulkan/VulkanConstants.h"
|
||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include "vulkan/utils/Image.h"
|
|
||||||
#include "vulkan/utils/Conversion.h"
|
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -137,8 +136,7 @@ std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
||||||
VulkanPlatform::ExternalImageMetadata const& metadata, uint32_t memoryTypeIndex,
|
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
||||||
VkImageUsageFlags usage) {
|
|
||||||
VulkanPlatform::ImageData data;
|
VulkanPlatform::ImageData data;
|
||||||
|
|
||||||
// if external format we need to specifiy it in the allocation
|
// if external format we need to specifiy it in the allocation
|
||||||
@@ -147,8 +145,8 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
const VkExternalFormatANDROID externalFormat = {
|
const VkExternalFormatANDROID externalFormat = {
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
// pass down the format (external means we don't have it VK defined)
|
.externalFormat = metadata
|
||||||
.externalFormat = metadata.externalFormat,
|
.externalFormat,// pass down the format (external means we don't have it VK defined)
|
||||||
};
|
};
|
||||||
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||||
@@ -156,7 +154,7 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
.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.pNext = &externalCreateInfo;
|
||||||
imageInfo.format = metadata.format;
|
imageInfo.format = metadata.format;
|
||||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
@@ -167,8 +165,10 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
};
|
};
|
||||||
imageInfo.mipLevels = 1;
|
imageInfo.mipLevels = 1;
|
||||||
imageInfo.arrayLayers = metadata.layers;
|
imageInfo.arrayLayers = metadata.layers;
|
||||||
imageInfo.samples = metadata.samples;
|
imageInfo.usage = metadata.usage;
|
||||||
imageInfo.usage = usage;
|
// In the unprotected case add R/W capabilities
|
||||||
|
if (metadata.isProtected == false)
|
||||||
|
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
|
||||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
@@ -186,12 +186,10 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
.image = data.first,
|
.image = data.first,
|
||||||
.buffer = VK_NULL_HANDLE,
|
.buffer = VK_NULL_HANDLE,
|
||||||
};
|
};
|
||||||
VkMemoryAllocateInfo allocInfo = {
|
VkMemoryAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
||||||
.pNext = &memoryDedicatedAllocateInfo,
|
.pNext = &memoryDedicatedAllocateInfo,
|
||||||
.allocationSize = metadata.allocationSize,
|
.allocationSize = metadata.allocationSize,
|
||||||
.memoryTypeIndex = memoryTypeIndex,
|
.memoryTypeIndex = metadata.memoryTypeBits};
|
||||||
};
|
|
||||||
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
||||||
@@ -199,12 +197,14 @@ VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevic
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace
|
} // namespace
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
namespace fvkandroid {
|
||||||
|
|
||||||
Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||||
AHardwareBuffer const* buffer, bool sRGB) noexcept {
|
|
||||||
|
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||||
|
bool sRGB) noexcept {
|
||||||
if (__builtin_available(android 26, *)) {
|
if (__builtin_available(android 26, *)) {
|
||||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||||
@@ -223,23 +223,12 @@ Platform::ExternalImageHandle VulkanPlatformAndroid::createExternalImage(
|
|||||||
return Platform::ExternalImageHandle{};
|
return Platform::ExternalImageHandle{};
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageDescAndroid VulkanPlatformAndroid::getExternalImageDesc(
|
} // namespace fvkandroid
|
||||||
ExternalImageHandleRef externalImage) const noexcept {
|
|
||||||
auto const* fvkExternalImage =
|
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
|
||||||
|
|
||||||
return {
|
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||||
.width = fvkExternalImage->width,
|
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||||
.height = fvkExternalImage->height,
|
|
||||||
.format = fvkExternalImage->format,
|
|
||||||
.usage = fvkExternalImage->usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMetadata(
|
|
||||||
ExternalImageHandleRef externalImage) {
|
|
||||||
auto const* fvkExternalImage =
|
auto const* fvkExternalImage =
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
|
|
||||||
ExternalImageMetadata metadata;
|
ExternalImageMetadata metadata;
|
||||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||||
@@ -253,8 +242,10 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
std::tie(metadata.format, metadata.usage) =
|
std::tie(metadata.format, metadata.usage) =
|
||||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||||
}
|
}
|
||||||
|
// In the unprotected case add R/W capabilities
|
||||||
metadata.samples = VK_SAMPLE_COUNT_1_BIT;
|
if (metadata.isProtected == false) {
|
||||||
|
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
||||||
@@ -264,11 +255,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||||
.pNext = &formatInfo,
|
.pNext = &formatInfo,
|
||||||
};
|
};
|
||||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(getDevice(), buffer, &properties);
|
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||||
<< static_cast<int32_t>(result);
|
<< static_cast<int32_t>(result);
|
||||||
|
|
||||||
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
||||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
||||||
<< "mismatched image format( " << metadata.format << ") and queried format("
|
<< "mismatched image format( " << metadata.format << ") and queried format("
|
||||||
@@ -279,140 +270,26 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatformAndroid::getExternalImageMet
|
|||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatformAndroid::ImageData VulkanPlatformAndroid::createExternalImageData(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
auto const* fvkExternalImage =
|
auto const* fvkExternalImage =
|
||||||
static_cast<ExternalImageVulkanAndroid const*>(externalImage.get());
|
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, getDevice(), metadata,
|
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata);
|
||||||
memoryTypeIndex, usage);
|
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||||
VkResult result = vkBindImageMemory(getDevice(), data.first, data.second, 0);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device, SamplerYcbcrConversion chroma,
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
uint32_t internalFormat, VkImage image, VkImageSubresourceRange range,
|
|
||||||
VkImageViewType viewType, VkComponentMapping swizzle){
|
|
||||||
VkExternalFormatANDROID externalFormat = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.externalFormat = internalFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
|
||||||
.pNext = &externalFormat,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
|
||||||
};
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
|
||||||
nullptr, &conversion);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create Ycbcr Conversion."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.conversion = conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.pNext = &samplerYcbcrConversionInfo,
|
|
||||||
.flags = 0,
|
|
||||||
.image = image,
|
|
||||||
.viewType = viewType,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.components = swizzle,
|
|
||||||
.subresourceRange = range,
|
|
||||||
};
|
|
||||||
VkImageView imageView;
|
|
||||||
result = vkCreateImageView(device, &viewInfo, VKALLOC, &imageView);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create VkImageView."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(
|
|
||||||
VkDevice device, SamplerYcbcrConversion chroma, SamplerParams params,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
VkExternalFormatANDROID externalFormat = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.externalFormat = internalFormat,
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureSwizzle const swizzleArray[] = {chroma.r, chroma.g, chroma.b, chroma.a};
|
|
||||||
VkSamplerYcbcrConversionCreateInfo conversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
|
|
||||||
.pNext = &externalFormat,
|
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
|
||||||
.ycbcrModel = fvkutils::getYcbcrModelConversion(chroma.ycbcrModel),
|
|
||||||
.ycbcrRange = fvkutils::getYcbcrRange(chroma.ycbcrRange),
|
|
||||||
.components = fvkutils::getSwizzleMap(swizzleArray),
|
|
||||||
.xChromaOffset = fvkutils::getChromaLocation(chroma.xChromaOffset),
|
|
||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
|
||||||
};
|
|
||||||
VkSamplerYcbcrConversion conversion = VK_NULL_HANDLE;
|
|
||||||
VkResult result = vkCreateSamplerYcbcrConversion(device, &conversionInfo,
|
|
||||||
nullptr, &conversion);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create Ycbcr Conversion."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
|
|
||||||
VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.conversion = conversion,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
||||||
.pNext = &samplerYcbcrConversionInfo,
|
|
||||||
.magFilter = fvkutils::getFilter(params.filterMag),
|
|
||||||
.minFilter = fvkutils::getFilter(params.filterMin),
|
|
||||||
.mipmapMode = fvkutils::getMipmapMode(params.filterMin),
|
|
||||||
.addressModeU = fvkutils::getWrapMode(params.wrapS),
|
|
||||||
.addressModeV = fvkutils::getWrapMode(params.wrapT),
|
|
||||||
.addressModeW = fvkutils::getWrapMode(params.wrapR),
|
|
||||||
.anisotropyEnable = params.anisotropyLog2 == 0 ? VK_FALSE : VK_TRUE,
|
|
||||||
.maxAnisotropy = (float)(1u << params.anisotropyLog2),
|
|
||||||
.compareEnable = fvkutils::getCompareEnable(params.compareMode),
|
|
||||||
.compareOp = fvkutils::getCompareOp(params.compareFunc),
|
|
||||||
.minLod = 0.0f,
|
|
||||||
.maxLod = fvkutils::getMaxLod(params.filterMin),
|
|
||||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
||||||
.unnormalizedCoordinates = VK_FALSE,
|
|
||||||
};
|
|
||||||
VkSampler sampler;
|
|
||||||
result = vkCreateSampler(device, &samplerInfo, VKALLOC, &sampler);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
|
||||||
<< "Unable to create sampler."
|
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
|
||||||
return sampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatformAndroid::getSwapchainInstanceExtensions() const {
|
|
||||||
return {
|
return {
|
||||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) const noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
|
|
||||||
@@ -424,26 +301,6 @@ VulkanPlatform::SurfaceBundle VulkanPlatformAndroid::createVkSurfaceKHR(void* na
|
|||||||
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
|
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkCreateAndroidSurfaceKHR with error=" << static_cast<int32_t>(result);
|
<< "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 {
|
namespace filament::backend {
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
ExtensionSet const ret = {
|
ExtensionSet const ret = {
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
|
VK_MVK_MACOS_SURFACE_EXTENSION_NAME, // TODO: replace with VK_EXT_metal_surface
|
||||||
@@ -70,24 +70,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
|||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, VkDevice device,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
|||||||
@@ -91,24 +91,11 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
|||||||
|
|
||||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||||
ExternalImageHandleRef externalImage, VkDevice device,
|
ExternalImageHandleRef externalImage, VkDevice device,
|
||||||
const ExternalImageMetadata& metadata, uint32_t memoryTypeIndex, VkImageUsageFlags usage) {
|
const ExternalImageMetadata& metadata) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSampler VulkanPlatform::createExternalSamplerImpl(VkDevice device,
|
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||||
SamplerYcbcrConversion chroma,
|
|
||||||
SamplerParams sampler,
|
|
||||||
uint32_t internalFormat) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView VulkanPlatform::createExternalImageViewImpl(VkDevice device,
|
|
||||||
SamplerYcbcrConversion chroma, uint32_t internalFormat, VkImage image,
|
|
||||||
VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl() {
|
|
||||||
VulkanPlatform::ExtensionSet const ret = {
|
VulkanPlatform::ExtensionSet const ret = {
|
||||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||||
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
||||||
@@ -126,7 +113,7 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensionsImpl(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHRImpl(void* nativeWindow,
|
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||||
VkInstance instance, uint64_t flags) noexcept {
|
VkInstance instance, uint64_t flags) noexcept {
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
|
||||||
|
|||||||
@@ -588,79 +588,6 @@ VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]) {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFilter getFilter(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFilter getFilter(SamplerMagFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMagFilter::NEAREST:
|
|
||||||
return VK_FILTER_NEAREST;
|
|
||||||
case SamplerMagFilter::LINEAR:
|
|
||||||
return VK_FILTER_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case SamplerWrapMode::REPEAT:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
case SamplerWrapMode::CLAMP_TO_EDGE:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
case SamplerWrapMode::MIRRORED_REPEAT:
|
|
||||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBool32 getCompareEnable(SamplerCompareMode mode) {
|
|
||||||
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getMaxLod(SamplerMinFilter filter) {
|
|
||||||
switch (filter) {
|
|
||||||
case SamplerMinFilter::NEAREST:
|
|
||||||
case SamplerMinFilter::LINEAR:
|
|
||||||
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
|
|
||||||
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
|
|
||||||
return 0.25f;
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
|
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
|
|
||||||
return VK_LOD_CLAMP_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) {
|
||||||
VkShaderStageFlags flags = 0x0;
|
VkShaderStageFlags flags = 0x0;
|
||||||
if (any(stageFlags & ShaderStageFlags::VERTEX)) flags |= VK_SHADER_STAGE_VERTEX_BIT;
|
if (any(stageFlags & ShaderStageFlags::VERTEX)) flags |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
|||||||
@@ -56,19 +56,6 @@ uint32_t getComponentCount(VkFormat format);
|
|||||||
VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]);
|
VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]);
|
||||||
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags);
|
||||||
|
|
||||||
// Needed by the Platform for external sampler creation
|
|
||||||
VkFilter getFilter(SamplerMinFilter filter);
|
|
||||||
VkFilter getFilter(SamplerMagFilter filter);
|
|
||||||
VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter);
|
|
||||||
VkSamplerAddressMode getWrapMode(SamplerWrapMode mode);
|
|
||||||
VkBool32 getCompareEnable(SamplerCompareMode mode);
|
|
||||||
float getMaxLod(SamplerMinFilter filter);
|
|
||||||
|
|
||||||
// Ycbcr related functions
|
|
||||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(SamplerYcbcrModelConversion model);
|
|
||||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range);
|
|
||||||
VkChromaLocation getChromaLocation(ChromaLocation loc);
|
|
||||||
|
|
||||||
inline VkImageViewType getViewType(SamplerType target) {
|
inline VkImageViewType getViewType(SamplerType target) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
|||||||
@@ -193,49 +193,6 @@ uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) {
|
|||||||
return mostSignificantBit((sampleCount - 1) & mask);
|
return mostSignificantBit((sampleCount - 1) & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSamplerYcbcrModelConversion getYcbcrModelConversion(
|
|
||||||
SamplerYcbcrModelConversion model) {
|
|
||||||
switch (model) {
|
|
||||||
case SamplerYcbcrModelConversion::RGB_IDENTITY:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_IDENTITY:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_709:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_601:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
|
|
||||||
case SamplerYcbcrModelConversion::YCBCR_2020:
|
|
||||||
return VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerYcbcrRange getYcbcrRange(SamplerYcbcrRange range) {
|
|
||||||
switch (range) {
|
|
||||||
case SamplerYcbcrRange::ITU_FULL:
|
|
||||||
return VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
|
|
||||||
case SamplerYcbcrRange::ITU_NARROW:
|
|
||||||
return VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkChromaLocation getChromaLocation(ChromaLocation loc) {
|
|
||||||
switch (loc) {
|
|
||||||
case ChromaLocation::COSITED_EVEN:
|
|
||||||
return VK_CHROMA_LOCATION_COSITED_EVEN;
|
|
||||||
case ChromaLocation::MIDPOINT:
|
|
||||||
return VK_CHROMA_LOCATION_MIDPOINT;
|
|
||||||
default:
|
|
||||||
assert_invariant(false &&
|
|
||||||
"Unknown data type, conversion is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend::fvkutils
|
} // namespace filament::backend::fvkutils
|
||||||
|
|
||||||
bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& b) {
|
bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& b) {
|
||||||
|
|||||||
@@ -1,66 +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_WEBGPUCONSTANTS_H
|
|
||||||
#define TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
|
||||||
|
|
||||||
#include <utils/Log.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
// FWGPU is short for Filament WebGPU
|
|
||||||
|
|
||||||
// turn on runtime validation, namely for debugging, that would normally not run (for release)
|
|
||||||
#define FWGPU_DEBUG_VALIDATION 0x00000001
|
|
||||||
// print/log system component details to the console, e.g. about the
|
|
||||||
// instance, surface, adapter, device, etc.
|
|
||||||
#define FWGPU_PRINT_SYSTEM 0x00000002
|
|
||||||
|
|
||||||
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
|
|
||||||
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
|
|
||||||
// order of calls).
|
|
||||||
#define FWGPU_DEBUG_FORCE_LOG_TO_I 0x00000004
|
|
||||||
|
|
||||||
// Useful default combinations
|
|
||||||
#define FWGPU_DEBUG_EVERYTHING 0xFFFFFFFF
|
|
||||||
|
|
||||||
#if defined(FILAMENT_BACKEND_DEBUG_FLAG)
|
|
||||||
#define FWGPU_DEBUG_FORWARDED_FLAG (FILAMENT_BACKEND_DEBUG_FLAG & FWGPU_DEBUG_EVERYTHING)
|
|
||||||
#else
|
|
||||||
#define FWGPU_DEBUG_FORWARDED_FLAG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define FWGPU_DEBUG_FLAGS FWGPU_DEBUG_FORWARDED_FLAG
|
|
||||||
#else
|
|
||||||
#define FWGPU_DEBUG_FLAGS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FWGPU_ENABLED(flags) (((FWGPU_DEBUG_FLAGS) & (flags)) == (flags))
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_DEBUG_FORCE_LOG_TO_I)
|
|
||||||
#define FWGPU_LOGI (utils::slog.i)
|
|
||||||
#define FWGPU_LOGD FWGPU_LOGI
|
|
||||||
#define FWGPU_LOGE FWGPU_LOGI
|
|
||||||
#define FWGPU_LOGW FWGPU_LOGI
|
|
||||||
#else
|
|
||||||
#define FWGPU_LOGE (utils::slog.e)
|
|
||||||
#define FWGPU_LOGW (utils::slog.w)
|
|
||||||
#define FWGPU_LOGD (utils::slog.d)
|
|
||||||
#define FWGPU_LOGI (utils::slog.i)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUCONSTANTS_H
|
|
||||||
@@ -14,254 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "webgpu/WebGPUDriver.h"
|
|
||||||
|
|
||||||
#include "webgpu/WebGPUConstants.h"
|
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
|
||||||
|
|
||||||
#include "CommandStreamDispatcher.h"
|
|
||||||
#include "DriverBase.h"
|
|
||||||
#include "private/backend/Dispatcher.h"
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
#include <math/mat3.h>
|
#include "webgpu/WebGPUDriver.h"
|
||||||
#include <utils/CString.h>
|
#include "CommandStreamDispatcher.h"
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <dawn/webgpu_cpp_print.h>
|
#include <stdint.h>
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string_view>
|
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
namespace {
|
Driver* WebGPUDriver::create() {
|
||||||
|
return new WebGPUDriver();
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printInstanceDetails(wgpu::Instance const& instance) {
|
|
||||||
wgpu::SupportedWGSLLanguageFeatures supportedWGSLLanguageFeatures{};
|
|
||||||
if (!instance.GetWGSLLanguageFeatures(&supportedWGSLLanguageFeatures)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU instance supported WGSL language features"
|
|
||||||
<< utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU instance supported WGSL language features ("
|
|
||||||
<< supportedWGSLLanguageFeatures.featureCount << "):" << utils::io::endl;
|
|
||||||
if (supportedWGSLLanguageFeatures.featureCount > 0 &&
|
|
||||||
supportedWGSLLanguageFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedWGSLLanguageFeatures.features,
|
|
||||||
supportedWGSLLanguageFeatures.features +
|
|
||||||
supportedWGSLLanguageFeatures.featureCount,
|
|
||||||
[](wgpu::WGSLLanguageFeatureName const featureName) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << featureName;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printLimit(std::string_view name, const std::variant<uint32_t, uint64_t> value) {
|
|
||||||
FWGPU_LOGI << " " << name.data() << ": ";
|
|
||||||
bool undefined = true;
|
|
||||||
if (std::holds_alternative<uint32_t>(value)) {
|
|
||||||
if (std::get<uint32_t>(value) != WGPU_LIMIT_U32_UNDEFINED) {
|
|
||||||
undefined = false;
|
|
||||||
FWGPU_LOGI << std::get<uint32_t>(value);
|
|
||||||
}
|
|
||||||
} else if (std::holds_alternative<uint64_t>(value)) {
|
|
||||||
if (std::get<uint64_t>(value) != WGPU_LIMIT_U64_UNDEFINED) {
|
|
||||||
undefined = false;
|
|
||||||
FWGPU_LOGI << std::get<uint64_t>(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (undefined) {
|
|
||||||
FWGPU_LOGI << "UNDEFINED";
|
|
||||||
}
|
|
||||||
FWGPU_LOGI << utils::io::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printLimits(wgpu::Limits const& limits) {
|
|
||||||
printLimit("maxTextureDimension1D", limits.maxTextureDimension1D);
|
|
||||||
printLimit("maxTextureDimension2D", limits.maxTextureDimension2D);
|
|
||||||
printLimit("maxTextureDimension3D", limits.maxTextureDimension3D);
|
|
||||||
printLimit("maxTextureArrayLayers", limits.maxTextureArrayLayers);
|
|
||||||
printLimit("maxBindGroups", limits.maxBindGroups);
|
|
||||||
printLimit("maxBindGroupsPlusVertexBuffers", limits.maxBindGroupsPlusVertexBuffers);
|
|
||||||
printLimit("maxBindingsPerBindGroup", limits.maxBindingsPerBindGroup);
|
|
||||||
printLimit("maxDynamicUniformBuffersPerPipelineLayout",
|
|
||||||
limits.maxDynamicUniformBuffersPerPipelineLayout);
|
|
||||||
printLimit("maxDynamicStorageBuffersPerPipelineLayout",
|
|
||||||
limits.maxDynamicStorageBuffersPerPipelineLayout);
|
|
||||||
printLimit("maxSampledTexturesPerShaderStage", limits.maxSampledTexturesPerShaderStage);
|
|
||||||
printLimit("maxSamplersPerShaderStage", limits.maxSamplersPerShaderStage);
|
|
||||||
printLimit("maxStorageBuffersPerShaderStage", limits.maxStorageBuffersPerShaderStage);
|
|
||||||
printLimit("maxStorageTexturesPerShaderStage", limits.maxStorageTexturesPerShaderStage);
|
|
||||||
printLimit("maxUniformBuffersPerShaderStage", limits.maxUniformBuffersPerShaderStage);
|
|
||||||
printLimit("maxUniformBufferBindingSize", limits.maxUniformBufferBindingSize);
|
|
||||||
printLimit("maxStorageBufferBindingSize", limits.maxStorageBufferBindingSize);
|
|
||||||
printLimit("minUniformBufferOffsetAlignment", limits.minUniformBufferOffsetAlignment);
|
|
||||||
printLimit("minStorageBufferOffsetAlignment", limits.minStorageBufferOffsetAlignment);
|
|
||||||
printLimit("maxVertexBuffers", limits.maxVertexBuffers);
|
|
||||||
printLimit("maxBufferSize", limits.maxBufferSize);
|
|
||||||
printLimit("maxVertexAttributes", limits.maxVertexAttributes);
|
|
||||||
printLimit("maxVertexBufferArrayStride", limits.maxVertexBufferArrayStride);
|
|
||||||
printLimit("maxInterStageShaderComponents", limits.maxInterStageShaderComponents);
|
|
||||||
printLimit("maxInterStageShaderVariables", limits.maxInterStageShaderVariables);
|
|
||||||
printLimit("maxColorAttachments", limits.maxColorAttachments);
|
|
||||||
printLimit("maxColorAttachmentBytesPerSample", limits.maxColorAttachmentBytesPerSample);
|
|
||||||
printLimit("maxComputeWorkgroupStorageSize", limits.maxComputeWorkgroupStorageSize);
|
|
||||||
printLimit("maxComputeInvocationsPerWorkgroup", limits.maxComputeInvocationsPerWorkgroup);
|
|
||||||
printLimit("maxComputeWorkgroupSizeX", limits.maxComputeWorkgroupSizeX);
|
|
||||||
printLimit("maxComputeWorkgroupSizeY", limits.maxComputeWorkgroupSizeY);
|
|
||||||
printLimit("maxComputeWorkgroupSizeZ", limits.maxComputeWorkgroupSizeZ);
|
|
||||||
printLimit("maxComputeWorkgroupsPerDimension", limits.maxComputeWorkgroupsPerDimension);
|
|
||||||
printLimit("maxStorageBuffersInVertexStage", limits.maxStorageBuffersInVertexStage);
|
|
||||||
printLimit("maxStorageTexturesInVertexStage", limits.maxStorageTexturesInVertexStage);
|
|
||||||
printLimit("maxStorageBuffersInFragmentStage", limits.maxStorageBuffersInFragmentStage);
|
|
||||||
printLimit("maxStorageTexturesInFragmentStage", limits.maxStorageTexturesInFragmentStage);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printAdapterDetails(wgpu::Adapter const& adapter) {
|
|
||||||
wgpu::DawnAdapterPropertiesPowerPreference powerPreferenceProperties{};
|
|
||||||
wgpu::AdapterInfo adapterInfo{};
|
|
||||||
adapterInfo.nextInChain = &powerPreferenceProperties;
|
|
||||||
if (!adapter.GetInfo(&adapterInfo)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU adapter info" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
std::stringstream backendTypeStream{};
|
|
||||||
backendTypeStream << adapterInfo.backendType;
|
|
||||||
std::stringstream adapterTypeStream{};
|
|
||||||
adapterTypeStream << adapterInfo.adapterType;
|
|
||||||
std::stringstream powerPreferenceStream{};
|
|
||||||
powerPreferenceStream << powerPreferenceProperties.powerPreference;
|
|
||||||
FWGPU_LOGI << "WebGPU adapter info:" << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " vendor: " << adapterInfo.vendor.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " architecture: " << adapterInfo.architecture.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " device: " << adapterInfo.device.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " description: " << adapterInfo.description.data << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " backend type: " << backendTypeStream.str().data() << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " adapter type: " << adapterTypeStream.str().data() << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " device ID: " << adapterInfo.deviceID << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " vendor ID: " << adapterInfo.vendorID << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " subgroup min size: " << adapterInfo.subgroupMinSize << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " subgroup max size: " << adapterInfo.subgroupMaxSize << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " compatibility mode: " << bool(adapterInfo.compatibilityMode)
|
|
||||||
<< utils::io::endl;
|
|
||||||
FWGPU_LOGI << " power preference: " << powerPreferenceStream.str() << utils::io::endl;
|
|
||||||
}
|
|
||||||
wgpu::SupportedFeatures supportedFeatures{};
|
|
||||||
adapter.GetFeatures(&supportedFeatures);
|
|
||||||
FWGPU_LOGI << "WebGPU adapter supported features (" << supportedFeatures.featureCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedFeatures.features,
|
|
||||||
supportedFeatures.features + supportedFeatures.featureCount,
|
|
||||||
[](wgpu::FeatureName const name) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << name;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wgpu::SupportedLimits supportedLimits{};
|
|
||||||
if (!adapter.GetLimits(&supportedLimits)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU adapter supported limits" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU adapter supported limits:" << utils::io::endl;
|
|
||||||
printLimits(supportedLimits.limits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printSurfaceCapabilitiesDetails(wgpu::SurfaceCapabilities const& capabilities) {
|
|
||||||
std::stringstream usages_stream{};
|
|
||||||
usages_stream << capabilities.usages;
|
|
||||||
FWGPU_LOGI << "WebGPU surface capabilities:" << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " surface usages: " << usages_stream.str().data() << utils::io::endl;
|
|
||||||
FWGPU_LOGI << " surface formats (" << capabilities.formatCount << "):" << utils::io::endl;
|
|
||||||
if (capabilities.formatCount > 0 && capabilities.formats != nullptr) {
|
|
||||||
std::for_each(capabilities.formats, capabilities.formats + capabilities.formatCount,
|
|
||||||
[](wgpu::TextureFormat const format) {
|
|
||||||
std::stringstream format_stream{};
|
|
||||||
format_stream << format;
|
|
||||||
FWGPU_LOGI << " " << format_stream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
FWGPU_LOGI << " surface present modes (" << capabilities.presentModeCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (capabilities.presentModeCount > 0 && capabilities.presentModes != nullptr) {
|
|
||||||
std::for_each(capabilities.presentModes,
|
|
||||||
capabilities.presentModes + capabilities.presentModeCount,
|
|
||||||
[](wgpu::PresentMode const presentMode) {
|
|
||||||
std::stringstream present_mode_stream{};
|
|
||||||
present_mode_stream << presentMode;
|
|
||||||
FWGPU_LOGI << " " << present_mode_stream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
FWGPU_LOGI << " surface alpha modes (" << capabilities.alphaModeCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (capabilities.alphaModeCount > 0 && capabilities.alphaModes != nullptr) {
|
|
||||||
std::for_each(capabilities.alphaModes,
|
|
||||||
capabilities.alphaModes + capabilities.alphaModeCount,
|
|
||||||
[](wgpu::CompositeAlphaMode const alphaMode) {
|
|
||||||
std::stringstream alpha_mode_stream{};
|
|
||||||
alpha_mode_stream << alphaMode;
|
|
||||||
FWGPU_LOGI << " " << alpha_mode_stream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
void printDeviceDetails(wgpu::Device const& device) {
|
|
||||||
wgpu::SupportedFeatures supportedFeatures{};
|
|
||||||
device.GetFeatures(&supportedFeatures);
|
|
||||||
FWGPU_LOGI << "WebGPU device supported features (" << supportedFeatures.featureCount
|
|
||||||
<< "):" << utils::io::endl;
|
|
||||||
if (supportedFeatures.featureCount > 0 && supportedFeatures.features != nullptr) {
|
|
||||||
std::for_each(supportedFeatures.features,
|
|
||||||
supportedFeatures.features + supportedFeatures.featureCount,
|
|
||||||
[](wgpu::FeatureName const name) {
|
|
||||||
std::stringstream nameStream{};
|
|
||||||
nameStream << name;
|
|
||||||
FWGPU_LOGI << " " << nameStream.str().data() << utils::io::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wgpu::SupportedLimits supportedLimits{};
|
|
||||||
if (!device.GetLimits(&supportedLimits)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU supported device limits" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGI << "WebGPU device supported limits:" << utils::io::endl;
|
|
||||||
printLimits(supportedLimits.limits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}// namespace
|
|
||||||
|
|
||||||
Driver* WebGPUDriver::create(WebGPUPlatform& platform) noexcept {
|
|
||||||
return new WebGPUDriver(platform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform) noexcept
|
WebGPUDriver::WebGPUDriver() noexcept = default;
|
||||||
: mPlatform(platform) {
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printInstanceDetails(mPlatform.getInstance());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
WebGPUDriver::~WebGPUDriver() noexcept = default;
|
||||||
|
|
||||||
@@ -356,188 +123,6 @@ void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh)
|
|||||||
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainS() noexcept {
|
|
||||||
return Handle<HwSwapChain>((Handle<HwSwapChain>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwSwapChain> WebGPUDriver::createSwapChainHeadlessS() noexcept {
|
|
||||||
return Handle<HwSwapChain>((Handle<HwSwapChain>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
|
||||||
return Handle<HwProgram>((Handle<HwProgram>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwFence> WebGPUDriver::createFenceS() noexcept {
|
|
||||||
return Handle<HwFence>((Handle<HwFence>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTimerQuery> WebGPUDriver::createTimerQueryS() noexcept {
|
|
||||||
return Handle<HwTimerQuery>((Handle<HwTimerQuery>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
|
||||||
return Handle<HwIndexBuffer>((Handle<HwIndexBuffer>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
|
||||||
return Handle<HwBufferObject>((Handle<HwBufferObject>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createRenderTargetS() noexcept {
|
|
||||||
return Handle<HwRenderTarget>((Handle<HwRenderTarget>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwVertexBuffer> WebGPUDriver::createVertexBufferS() noexcept {
|
|
||||||
return Handle<HwVertexBuffer>((Handle<HwVertexBuffer>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwDescriptorSet> WebGPUDriver::createDescriptorSetS() noexcept {
|
|
||||||
return Handle<HwDescriptorSet>((Handle<HwDescriptorSet>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderPrimitive> WebGPUDriver::createRenderPrimitiveS() noexcept {
|
|
||||||
return Handle<HwRenderPrimitive>((Handle<HwRenderPrimitive>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
|
||||||
return Handle<HwVertexBufferInfo>((Handle<HwVertexBufferInfo>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
|
||||||
return Handle<HwRenderTarget>((Handle<HwRenderTarget>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcept {
|
|
||||||
return Handle<HwDescriptorSetLayout>(
|
|
||||||
(Handle<HwDescriptorSetLayout>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
|
||||||
mSurface= mPlatform.createSurface(nativeWindow, flags);
|
|
||||||
mAdapter = mPlatform.requestAdapter(mSurface);
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printAdapterDetails(mAdapter);
|
|
||||||
wgpu::SurfaceCapabilities surfaceCapabilities{};
|
|
||||||
if (!mSurface.GetCapabilities(mAdapter, &surfaceCapabilities)) {
|
|
||||||
FWGPU_LOGW << "Failed to get WebGPU surface capabilities" << utils::io::endl;
|
|
||||||
} else {
|
|
||||||
printSurfaceCapabilitiesDetails(surfaceCapabilities);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
mDevice = mPlatform.requestDevice(mAdapter);
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
|
||||||
printDeviceDetails(mDevice);
|
|
||||||
#endif
|
|
||||||
mQueue = mDevice.GetQueue();
|
|
||||||
// TODO configure the surface (maybe before or after creating the swapchain?
|
|
||||||
// how do we get the surface extent?)
|
|
||||||
// TODO actually create the swapchain
|
|
||||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
|
||||||
"background components have been instantiated/selected, such as surface/screen, "
|
|
||||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
|
||||||
<< utils::io::endl;
|
|
||||||
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
|
||||||
FWGPU_LOGI << "If the FILAMENT_BACKEND_DEBUG_FLAG variable were set with the " << utils::io::hex
|
|
||||||
<< FWGPU_PRINT_SYSTEM << utils::io::dec
|
|
||||||
<< " bit flag on during build time the application would print system details "
|
|
||||||
"about the selected graphics device, surface, etc. To see this try "
|
|
||||||
"rebuilding Filament with that flag, e.g. ./build.sh -x "
|
|
||||||
<< FWGPU_PRINT_SYSTEM << " ..." << utils::io::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
|
||||||
uint32_t height, uint64_t flags) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
|
|
||||||
uint8_t attributeCount, AttributeArray attributes) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
|
|
||||||
Handle<HwVertexBufferInfo> vbih) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
|
||||||
uint32_t indexCount, BufferUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
|
||||||
BufferObjectBinding bindingType, BufferUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
|
||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
|
||||||
TextureUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
|
||||||
uint8_t baseLevel, uint8_t levelCount) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
|
||||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
|
||||||
backend::TextureSwizzle a) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
Platform::ExternalImageHandleRef externalImage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
void* externalImage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
|
||||||
void* image, uint32_t plane) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
|
||||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
|
||||||
uint32_t depth, TextureUsage usage) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
|
||||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
|
||||||
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
|
||||||
TargetBufferInfo depth, TargetBufferInfo stencil) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
|
|
||||||
backend::DescriptorSetLayout&& info) {}
|
|
||||||
|
|
||||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
|
||||||
Handle<HwDescriptorSetLayout> dslh) {}
|
|
||||||
|
|
||||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -655,14 +240,6 @@ size_t WebGPUDriver::getMaxUniformBufferSize() {
|
|||||||
return 16384u;
|
return 16384u;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WebGPUDriver::getMaxTextureSize(SamplerType target) {
|
|
||||||
return 2048u;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
|
||||||
return 256u;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
scheduleDestroy(std::move(p));
|
scheduleDestroy(std::move(p));
|
||||||
|
|||||||
@@ -17,44 +17,26 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#ifndef TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#define TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
|
|
||||||
#include <backend/platforms/WebGPUPlatform.h>
|
|
||||||
|
|
||||||
#include "DriverBase.h"
|
|
||||||
#include "private/backend/Dispatcher.h"
|
|
||||||
#include "private/backend/Driver.h"
|
#include "private/backend/Driver.h"
|
||||||
#include <backend/DriverEnums.h>
|
#include "DriverBase.h"
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
/**
|
|
||||||
* WebGPU backend (driver) implementation
|
|
||||||
*/
|
|
||||||
class WebGPUDriver final : public DriverBase {
|
class WebGPUDriver final : public DriverBase {
|
||||||
public:
|
WebGPUDriver() noexcept;
|
||||||
~WebGPUDriver() noexcept override;
|
~WebGPUDriver() noexcept override;
|
||||||
|
Dispatcher getDispatcher() const noexcept final;
|
||||||
|
|
||||||
[[nodiscard]] Dispatcher getDispatcher() const noexcept final;
|
public:
|
||||||
[[nodiscard]] static Driver* create(WebGPUPlatform& platform) noexcept;
|
static Driver* create();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit WebGPUDriver(WebGPUPlatform& platform) noexcept;
|
ShaderModel getShaderModel() const noexcept final;
|
||||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
ShaderLanguage getShaderLanguage() const noexcept final;
|
||||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
|
||||||
|
|
||||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
uint64_t nextFakeHandle = 1;
|
||||||
// handled in the WebGPUPlatform
|
|
||||||
WebGPUPlatform& mPlatform;
|
|
||||||
wgpu::Surface mSurface = nullptr;
|
|
||||||
wgpu::Adapter mAdapter = nullptr;
|
|
||||||
wgpu::Device mDevice = nullptr;
|
|
||||||
wgpu::Queue mQueue = nullptr;
|
|
||||||
uint64_t mNextFakeHandle = 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver interface
|
* Driver interface
|
||||||
@@ -63,19 +45,20 @@ private:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
friend class ConcreteDispatcher;
|
friend class ConcreteDispatcher;
|
||||||
|
|
||||||
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
|
||||||
UTILS_ALWAYS_INLINE inline void methodName(paramsDecl);
|
UTILS_ALWAYS_INLINE inline void methodName(paramsDecl);
|
||||||
|
|
||||||
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \
|
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \
|
||||||
RetType methodName(paramsDecl) override;
|
RetType methodName(paramsDecl) override;
|
||||||
|
|
||||||
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
|
||||||
RetType methodName##S() noexcept override; \
|
RetType methodName##S() noexcept override { \
|
||||||
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl);
|
return RetType((RetType::HandleId)nextFakeHandle++); } \
|
||||||
|
UTILS_ALWAYS_INLINE inline void methodName##R(RetType, paramsDecl) { }
|
||||||
|
|
||||||
#include "private/backend/DriverAPI.inc"
|
#include "private/backend/DriverAPI.inc"
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace filament::backend
|
} // namespace filament
|
||||||
|
|
||||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
#endif // TNT_FILAMENT_BACKEND_WEBGPUDRIVER_H
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 "webgpu/WebGPUPlatform.h"
|
||||||
|
#include "webgpu/WebGPUDriver.h"
|
||||||
|
|
||||||
|
#include "utils/Log.h"
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
Driver* WebGPUPlatform::createDriver(void* const sharedContext , const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
|
wgpu::InstanceDescriptor instance_descriptor {};
|
||||||
|
wgpu::Instance instance = wgpu::CreateInstance(&instance_descriptor);
|
||||||
|
if (instance) {
|
||||||
|
utils::slog.i << " WebGPU instance created\n";
|
||||||
|
} else {
|
||||||
|
utils::slog.e << " WebGPU instance failed to create\n";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return WebGPUDriver::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filament
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/Platform.h>
|
||||||
|
|
||||||
|
#include "webgpu/webgpu_cpp.h"
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class WebGPUPlatform
|
||||||
|
final : public Platform {
|
||||||
|
public:
|
||||||
|
|
||||||
|
int getOSVersion() const noexcept final { return 0; }
|
||||||
|
|
||||||
|
~WebGPUPlatform() noexcept override = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament
|
||||||
|
|
||||||
|
#endif // TNT_FILAMENT_BACKEND_WEBGPUPLATFORM_H
|
||||||