Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3308ec7e34 | ||
|
|
84980d89af | ||
|
|
60640be5e8 | ||
|
|
5f730ac173 | ||
|
|
e12ed900d0 | ||
|
|
78487f4836 | ||
|
|
25e9802fd5 | ||
|
|
dacd03ce42 | ||
|
|
c9cfc63df0 | ||
|
|
9c69cb8484 | ||
|
|
8ea4cb50d2 | ||
|
|
4f8080ead2 | ||
|
|
34ebe45e2a | ||
|
|
bb3e3df2f4 |
@@ -0,0 +1,68 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BracedInitializerIndentWidth: 4
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 100
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
PackConstructorInitializers: Never
|
||||
+10
-2
@@ -1,7 +1,15 @@
|
||||
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||
;;; 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)))
|
||||
(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))))
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
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_size = 4
|
||||
max_line_length = 100
|
||||
|
||||
@@ -104,3 +104,14 @@ jobs:
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
path: ./out/renderdiff_tests
|
||||
|
||||
validate-wgsl-pipeline:
|
||||
name: validate-wgsl-pipeline
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: ./build.sh -W debug test_filamat
|
||||
- name: Run test
|
||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.58.1'
|
||||
pod 'Filament', '~> 1.58.0'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -9,6 +9,9 @@ Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
|
||||
## v1.58.1
|
||||
|
||||
|
||||
## v1.58.0
|
||||
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
## v1.57.3
|
||||
|
||||
@@ -11,6 +11,13 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
message("Library filamat ignores Vulkan settings")
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
add_library(webgpu_dawn STATIC IMPORTED)
|
||||
set_target_properties(webgpu_dawn PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libwebgpu_dawn.a)
|
||||
endif()
|
||||
|
||||
|
||||
add_library(${FILAMAT_FLAVOR} STATIC IMPORTED)
|
||||
set_target_properties(${FILAMAT_FLAVOR} PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/lib${FILAMAT_FLAVOR}.a)
|
||||
@@ -50,4 +57,5 @@ target_link_libraries(filamat-jni
|
||||
utils
|
||||
log
|
||||
smol-v
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:webgpu_dawn> # for tint
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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.
|
||||
|
||||
|
||||
@@ -541,6 +541,7 @@ function build_android {
|
||||
./gradlew \
|
||||
-Pcom.google.android.filament.dist-dir=../out/android-debug/filament \
|
||||
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
:filamat-android:assembleDebug
|
||||
|
||||
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
|
||||
@@ -591,6 +592,7 @@ function build_android {
|
||||
./gradlew \
|
||||
-Pcom.google.android.filament.dist-dir=../out/android-release/filament \
|
||||
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
:filamat-android:assembleRelease
|
||||
|
||||
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
|
||||
|
||||
@@ -233,7 +233,10 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
elseif (APPLE OR IOS)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm)
|
||||
elseif (ANDROID)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp)
|
||||
list(APPEND SRCS
|
||||
include/backend/platforms/VulkanPlatformAndroid.h
|
||||
src/vulkan/platform/VulkanPlatformAndroid.cpp
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -458,6 +461,7 @@ if (APPLE OR LINUX)
|
||||
test/ShaderGenerator.cpp
|
||||
test/TrianglePrimitive.cpp
|
||||
test/Arguments.cpp
|
||||
test/Lifetimes.cpp
|
||||
test/test_FeedbackLoops.cpp
|
||||
test/test_Blit.cpp
|
||||
test/test_MissingRequiredAttributes.cpp
|
||||
|
||||
@@ -182,6 +182,7 @@ enum class ShaderLanguage {
|
||||
SPIRV = 2,
|
||||
MSL = 3,
|
||||
METAL_LIBRARY = 4,
|
||||
WGSL = 5,
|
||||
};
|
||||
|
||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||
@@ -196,6 +197,8 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
|
||||
return "MSL";
|
||||
case ShaderLanguage::METAL_LIBRARY:
|
||||
return "Metal precompiled library";
|
||||
case ShaderLanguage::WGSL:
|
||||
return "WGSL";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -347,18 +347,20 @@ public:
|
||||
*/
|
||||
uint32_t memoryTypeBits;
|
||||
};
|
||||
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
|
||||
virtual ExternalImageMetadata getExternalImageMetadata(ExternalImageHandleRef externalImage);
|
||||
|
||||
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||
virtual ImageData createExternalImage(void* externalImage,
|
||||
virtual ImageData createExternalImageData(ExternalImageHandleRef externalImage,
|
||||
const ExternalImageMetadata& metadata);
|
||||
|
||||
private:
|
||||
static ExtensionSet getSwapchainInstanceExtensions();
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage,
|
||||
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(ExternalImageHandleRef externalImage,
|
||||
VkDevice device);
|
||||
static ImageData createExternalImageImpl(void* externalImage, VkDevice device,
|
||||
const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata);
|
||||
|
||||
static ImageData createExternalImageDataImpl(ExternalImageHandleRef externalImage,
|
||||
VkDevice device, const ExternalImageMetadata& metadata);
|
||||
|
||||
// Platform dependent helper methods
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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_VULKAN_PLATFORM_ANDROID_H
|
||||
#define TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend::fvkandroid {
|
||||
|
||||
struct ExternalImageVulkanAndroid : public Platform::ExternalImage {
|
||||
AHardwareBuffer* aHardwareBuffer = nullptr;
|
||||
bool sRGB = false;
|
||||
unsigned int width; // Texture width
|
||||
unsigned int height; // Texture height
|
||||
TextureFormat format; // Texture format
|
||||
TextureUsage usage; // Texture usage flags
|
||||
|
||||
protected:
|
||||
~ExternalImageVulkanAndroid() override;
|
||||
};
|
||||
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept;
|
||||
|
||||
} // namespace filament::backend::fvkandroid
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PLATFORMS_VULKAN_PLATFORM_ANDROID_H
|
||||
@@ -138,6 +138,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
|
||||
case ShaderLanguage::ESSL1:
|
||||
case ShaderLanguage::ESSL3:
|
||||
case ShaderLanguage::SPIRV:
|
||||
case ShaderLanguage::WGSL:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#include <dlfcn.h>
|
||||
#include <memory>
|
||||
|
||||
// This is to ensure that linking during compilation will not fail even if
|
||||
// OSMesaGetProcAddress is not linked.
|
||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
using namespace backend;
|
||||
@@ -51,10 +55,10 @@ private:
|
||||
using GetProcAddressFunc = OSMESAproc (*)(const char* funcName);
|
||||
|
||||
public:
|
||||
CreateContextFunc OSMesaCreateContext;
|
||||
DestroyContextFunc OSMesaDestroyContext;
|
||||
MakeCurrentFunc OSMesaMakeCurrent;
|
||||
GetProcAddressFunc OSMesaGetProcAddress;
|
||||
CreateContextFunc fOSMesaCreateContext;
|
||||
DestroyContextFunc fOSMesaDestroyContext;
|
||||
MakeCurrentFunc fOSMesaMakeCurrent;
|
||||
GetProcAddressFunc fOSMesaGetProcAddress;
|
||||
|
||||
OSMesaAPI() {
|
||||
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||
@@ -65,18 +69,25 @@ public:
|
||||
}
|
||||
}
|
||||
if (mLib) {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
// Loading from a libosmesa.os
|
||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
// Filament is built into a .so
|
||||
fOSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
}
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(OSMesaGetProcAddress)
|
||||
<< "Unable to against libOSMesa to create a software GL context";
|
||||
if (!fOSMesaGetProcAddress) {
|
||||
// Statically linking osmesa
|
||||
fOSMesaGetProcAddress = OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext");
|
||||
OSMesaDestroyContext =
|
||||
(DestroyContextFunc) OSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
OSMesaMakeCurrent = (MakeCurrentFunc) OSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||
FILAMENT_CHECK_PRECONDITION(fOSMesaGetProcAddress)
|
||||
<< "Unable to link against libOSMesa to create a software GL context";
|
||||
|
||||
fOSMesaCreateContext = (CreateContextFunc) fOSMesaGetProcAddress("OSMesaCreateContext");
|
||||
fOSMesaDestroyContext =
|
||||
(DestroyContextFunc) fOSMesaGetProcAddress("OSMesaDestroyContext");
|
||||
fOSMesaMakeCurrent = (MakeCurrentFunc) fOSMesaGetProcAddress("OSMesaMakeCurrent");
|
||||
}
|
||||
|
||||
~OSMesaAPI() {
|
||||
@@ -97,7 +108,7 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr)
|
||||
<< "shared GL context is not supported with PlatformOSMesa";
|
||||
mContext = api->OSMesaCreateContext(GL_RGBA, NULL);
|
||||
mContext = api->fOSMesaCreateContext(GL_RGBA, NULL);
|
||||
|
||||
// We need to do a no-op makecurrent here so that the context will be in a correct state before
|
||||
// any GL calls.
|
||||
@@ -113,7 +124,7 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext,
|
||||
|
||||
void PlatformOSMesa::terminate() noexcept {
|
||||
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
|
||||
api->OSMesaDestroyContext(mContext);
|
||||
api->fOSMesaDestroyContext(mContext);
|
||||
delete api;
|
||||
mOsMesaApi = nullptr;
|
||||
|
||||
@@ -141,7 +152,7 @@ bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain,
|
||||
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
|
||||
OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain;
|
||||
|
||||
auto result = api->OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(),
|
||||
auto result = api->fOSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(),
|
||||
BACKING_GL_TYPE, impl->width, impl->height);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == GL_TRUE) << "OSMesaMakeCurrent failed!";
|
||||
|
||||
|
||||
@@ -560,14 +560,6 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th,
|
||||
Platform::ExternalImageHandleRef externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
// FIXME: implement createTextureExternalImage2R
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||
if (metadata.isProtected) {
|
||||
usage |= backend::TextureUsage::PROTECTED;
|
||||
@@ -577,15 +569,23 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
|
||||
assert_invariant(height == metadata.height);
|
||||
assert_invariant(fvkutils::getVkFormat(format) == metadata.format);
|
||||
|
||||
const auto& data = mPlatform->createExternalImage(externalImage, metadata);
|
||||
const auto& data = mPlatform->createExternalImageData(externalImage, metadata);
|
||||
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, 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,
|
||||
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
|
||||
|
||||
texture.inc();
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
// not supported in this backend
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane) {
|
||||
@@ -1266,10 +1266,9 @@ void VulkanDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
mBlitter.blit(VK_FILTER_LINEAR, dst, dstOffsets, src, srcOffsets);
|
||||
}
|
||||
|
||||
level++;
|
||||
srcw = dstw;
|
||||
srch = dsth;
|
||||
} while ((srcw > 1 || srch > 1) && level < t->levels);
|
||||
} while ((srcw > 1 || srch > 1) && ++level < t->levels - 1);
|
||||
}
|
||||
|
||||
void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
|
||||
@@ -978,13 +978,13 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
||||
void* externalImage) {
|
||||
ExternalImageHandleRef externalImage) {
|
||||
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata);
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageData(
|
||||
ExternalImageHandleRef externalImage, const ExternalImageMetadata& metadata) {
|
||||
return createExternalImageDataImpl(externalImage, mImpl->mDevice, metadata);
|
||||
}
|
||||
|
||||
#undef SWAPCHAIN_RET_FUNC
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||
#include <private/backend/BackendUtilsAndroid.h>
|
||||
|
||||
#include "vulkan/VulkanConstants.h"
|
||||
|
||||
#include <utils/Panic.h>
|
||||
@@ -24,17 +28,44 @@
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <android/native_window.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
|
||||
VkImageUsageFlags& usage, bool& isProtected) {
|
||||
|
||||
VkFormat transformVkFormat(VkFormat format, bool sRGB) {
|
||||
if (!sRGB) {
|
||||
return format;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
break;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8_SRGB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
bool isProtectedFromUsage(uint64_t usage) {
|
||||
return (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) ? true : false;
|
||||
}
|
||||
|
||||
std::pair<VkFormat, VkImageUsageFlags> getVKFormatAndUsage(const AHardwareBuffer_Desc& desc,
|
||||
bool sRGB) {
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImageUsageFlags usage = 0;
|
||||
// Refer to "11.2.17. External Memory Handle Types" in the spec, and
|
||||
// Tables 13/14 for how the following derivation works.
|
||||
bool isDepthFormat = false;
|
||||
isProtected = false;
|
||||
switch (desc.format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -82,6 +113,8 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
|
||||
format = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
format = transformVkFormat(format, sRGB);
|
||||
|
||||
// The following only concern usage flags derived from Table 14.
|
||||
usage = 0;
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||
@@ -98,16 +131,13 @@ void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
|
||||
usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
|
||||
isProtected = true;
|
||||
}
|
||||
|
||||
return { format, usage };
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ImageData allocateExternalImage(AHardwareBuffer* buffer, VkDevice device,
|
||||
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
||||
VulkanPlatform::ImageData data;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalBuffer);
|
||||
|
||||
// if external format we need to specifiy it in the allocation
|
||||
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
|
||||
@@ -140,7 +170,7 @@ VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
|
||||
if (metadata.isProtected == false)
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
VkResult result = vkCreateImage(device, &imageInfo, allocator, &data.first);
|
||||
VkResult result = vkCreateImage(device, &imageInfo, VKALLOC, &data.first);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkCreateImage failed with error=" << static_cast<int32_t>(result);
|
||||
|
||||
@@ -160,27 +190,57 @@ VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
|
||||
.pNext = &memoryDedicatedAllocateInfo,
|
||||
.allocationSize = metadata.allocationSize,
|
||||
.memoryTypeIndex = metadata.memoryTypeBits};
|
||||
result = vkAllocateMemory(device, &allocInfo, allocator, &data.second);
|
||||
result = vkAllocateMemory(device, &allocInfo, VKALLOC, &data.second);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkAllocateMemory failed with error=" << static_cast<int32_t>(result);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
} // namespace
|
||||
|
||||
namespace fvkandroid {
|
||||
|
||||
ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() = default;
|
||||
|
||||
Platform::ExternalImageHandle createExternalImage(AHardwareBuffer const* buffer,
|
||||
bool sRGB) noexcept {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc hardwareBufferDescription = {};
|
||||
AHardwareBuffer_describe(buffer, &hardwareBufferDescription);
|
||||
|
||||
auto* const p = new (std::nothrow) ExternalImageVulkanAndroid;
|
||||
p->aHardwareBuffer = const_cast<AHardwareBuffer*>(buffer);
|
||||
p->sRGB = sRGB;
|
||||
p->height = hardwareBufferDescription.height;
|
||||
p->width = hardwareBufferDescription.width;
|
||||
TextureFormat textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
||||
p->format = textureFormat;
|
||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
||||
return Platform::ExternalImageHandle{ p };
|
||||
}
|
||||
|
||||
return Platform::ExternalImageHandle{};
|
||||
}
|
||||
|
||||
} // namespace fvkandroid
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
|
||||
VkDevice device) {
|
||||
ExternalImageMetadata metadata;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalImage);
|
||||
AHardwareBuffer* buffer = fvkExternalImage->aHardwareBuffer;
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc bufferDesc;
|
||||
AHardwareBuffer_describe(buffer, &bufferDesc);
|
||||
metadata.width = bufferDesc.width;
|
||||
metadata.height = bufferDesc.height;
|
||||
metadata.layers = bufferDesc.layers;
|
||||
|
||||
getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected);
|
||||
metadata.isProtected = isProtectedFromUsage(bufferDesc.usage);
|
||||
std::tie(metadata.format, metadata.usage) =
|
||||
getVKFormatAndUsage(bufferDesc, fvkExternalImage->sRGB);
|
||||
}
|
||||
// In the unprotected case add R/W capabilities
|
||||
if (metadata.isProtected == false) {
|
||||
@@ -197,20 +257,25 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm
|
||||
};
|
||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||
<< static_cast<int32_t>(result);
|
||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format)
|
||||
<< "mismatched image format for external image (AHB)";
|
||||
<< "vkGetAndroidHardwareBufferProperties failed with error="
|
||||
<< static_cast<int32_t>(result);
|
||||
|
||||
VkFormat bufferPropertiesFormat = transformVkFormat(formatInfo.format, fvkExternalImage->sRGB);
|
||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == bufferPropertiesFormat)
|
||||
<< "mismatched image format( " << metadata.format << ") and queried format("
|
||||
<< bufferPropertiesFormat << ") for external image (AHB)";
|
||||
metadata.externalFormat = formatInfo.externalFormat;
|
||||
metadata.allocationSize = properties.allocationSize;
|
||||
metadata.memoryTypeBits = properties.memoryTypeBits;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
ImageData data = allocateExternalImage(externalImage, device, allocator, metadata);
|
||||
auto const* fvkExternalImage =
|
||||
static_cast<fvkandroid::ExternalImageVulkanAndroid const*>(externalImage.get());
|
||||
ImageData data = allocateExternalImage(fvkExternalImage->aHardwareBuffer, device, metadata);
|
||||
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkBindImageMemory error=" << static_cast<int32_t>(result);
|
||||
|
||||
@@ -64,12 +64,12 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
void* externalImage, VkDevice device) {
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ using namespace bluevk;
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
void* externalImage, VkDevice device) {
|
||||
ExternalImageHandleRef externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageDataImpl(
|
||||
ExternalImageHandleRef externalImage, VkDevice device,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ ShaderModel WebGPUDriver::getShaderModel() const noexcept {
|
||||
}
|
||||
|
||||
ShaderLanguage WebGPUDriver::getShaderLanguage() const noexcept {
|
||||
return ShaderLanguage::ESSL3;
|
||||
return ShaderLanguage::WGSL;
|
||||
}
|
||||
|
||||
// explicit instantiation of the Dispatcher
|
||||
@@ -131,9 +131,11 @@ Handle<HwStream> WebGPUDriver::createStreamAcquired() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void WebGPUDriver::setAcquiredImage(Handle<HwStream> sh, void* image,
|
||||
CallbackHandler* handler, StreamCallback cb, void* userData) {
|
||||
}
|
||||
void WebGPUDriver::setAcquiredImage(Handle<HwStream> sh, void* image, const math::mat3f& transform,
|
||||
CallbackHandler* handler, StreamCallback cb, void* userData) {}
|
||||
|
||||
void WebGPUDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh,
|
||||
BufferObjectStreamDescriptor&& streams) {}
|
||||
|
||||
void WebGPUDriver::setStreamDimensions(Handle<HwStream> sh, uint32_t width, uint32_t height) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 "Lifetimes.h"
|
||||
|
||||
#include "backend/Platform.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
RenderFrame::RenderFrame(filament::backend::DriverApi& api): mApi(api) {
|
||||
mApi.beginFrame(0, 0, 0);
|
||||
}
|
||||
|
||||
RenderFrame::~RenderFrame() {
|
||||
mApi.endFrame(0);
|
||||
}
|
||||
|
||||
Cleanup::Cleanup(filament::backend::DriverApi& driverApi) : mDriverApi(driverApi) {}
|
||||
|
||||
Cleanup::~Cleanup() {
|
||||
for (const auto swapChain: mSwapChains) {
|
||||
mDriverApi.destroySwapChain(swapChain);
|
||||
}
|
||||
for (const auto descriptorSet : mDescriptorSets) {
|
||||
mDriverApi.destroyDescriptorSet(descriptorSet);
|
||||
}
|
||||
for (const auto descriptorSetLayout : mDescriptorSetLayouts) {
|
||||
mDriverApi.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
}
|
||||
for (const auto bufferObject : mBufferObjects) {
|
||||
mDriverApi.destroyBufferObject(bufferObject);
|
||||
}
|
||||
for (const auto program : mPrograms) {
|
||||
mDriverApi.destroyProgram(program);
|
||||
}
|
||||
for (const auto texture : mTextures) {
|
||||
mDriverApi.destroyTexture(texture);
|
||||
}
|
||||
for (const auto renderTarget : mRenderTargets) {
|
||||
mDriverApi.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
for (const auto& callback : mCallbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::SwapChainHandle handle) {
|
||||
mSwapChains.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::DescriptorSetHandle handle) {
|
||||
mDescriptorSets.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(
|
||||
filament::backend::DescriptorSetLayoutHandle handle) {
|
||||
mDescriptorSetLayouts.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::BufferObjectHandle handle) {
|
||||
mBufferObjects.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::ProgramHandle handle) {
|
||||
mPrograms.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::TextureHandle handle) {
|
||||
mTextures.push_back(handle);
|
||||
}
|
||||
template <>
|
||||
void Cleanup::addInternal(filament::backend::RenderTargetHandle handle) {
|
||||
mRenderTargets.push_back(handle);
|
||||
}
|
||||
|
||||
void Cleanup::addPostCall(std::function<void()> callback){
|
||||
mCallbacks.emplace_back(std::move(callback));
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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_LIFETIMES_H
|
||||
#define TNT_LIFETIMES_H
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "backend/Handle.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
#include "BackendTest.h"
|
||||
|
||||
class RenderFrame {
|
||||
public:
|
||||
explicit RenderFrame(filament::backend::DriverApi& api);
|
||||
~RenderFrame();
|
||||
|
||||
RenderFrame(RenderFrame const& rhs) noexcept = delete;
|
||||
RenderFrame& operator=(RenderFrame const& rhs) noexcept = delete;
|
||||
RenderFrame(RenderFrame const&& rhs) noexcept = delete;
|
||||
RenderFrame& operator=(RenderFrame const&& rhs) noexcept = delete;
|
||||
|
||||
private:
|
||||
filament::backend::DriverApi& mApi;
|
||||
};
|
||||
|
||||
class Cleanup {
|
||||
public:
|
||||
/**
|
||||
* @param driverApi Must be valid for the entire lifetime of the Cleanup object.
|
||||
*/
|
||||
explicit Cleanup(filament::backend::DriverApi& driverApi);
|
||||
~Cleanup();
|
||||
|
||||
template <typename HandleType>
|
||||
filament::backend::Handle<HandleType> add(filament::backend::Handle<HandleType> handle);
|
||||
|
||||
void addPostCall(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
template <typename HandleType>
|
||||
void addInternal(filament::backend::Handle<HandleType> handle);
|
||||
|
||||
filament::backend::DriverApi & mDriverApi;
|
||||
|
||||
std::vector<filament::backend::SwapChainHandle> mSwapChains;
|
||||
std::vector<filament::backend::DescriptorSetHandle> mDescriptorSets;
|
||||
std::vector<filament::backend::DescriptorSetLayoutHandle> mDescriptorSetLayouts;
|
||||
std::vector<filament::backend::BufferObjectHandle> mBufferObjects;
|
||||
std::vector<filament::backend::ProgramHandle> mPrograms;
|
||||
std::vector<filament::backend::TextureHandle> mTextures;
|
||||
std::vector<filament::backend::RenderTargetHandle> mRenderTargets;
|
||||
|
||||
std::vector<std::function<void()>> mCallbacks;
|
||||
};
|
||||
|
||||
template <typename HandleType>
|
||||
filament::backend::Handle<HandleType> Cleanup::add(filament::backend::Handle<HandleType> handle) {
|
||||
addInternal(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
#endif //TNT_LIFETIMES_H
|
||||
@@ -30,7 +30,8 @@ enum class Backend : uint8_t {
|
||||
OPENGL = 1,
|
||||
VULKAN = 2,
|
||||
METAL = 3,
|
||||
NOOP = 4,
|
||||
WEBGPU = 4,
|
||||
NOOP = 5,
|
||||
};
|
||||
|
||||
struct NativeView {
|
||||
|
||||
@@ -90,6 +90,9 @@ ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment, Backe
|
||||
case Backend::METAL:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::MSL;
|
||||
break;
|
||||
case Backend::WEBGPU:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::WGSL;
|
||||
break;
|
||||
case Backend::NOOP:
|
||||
mShaderLanguage = filament::backend::ShaderLanguage::ESSL3;
|
||||
break;
|
||||
@@ -115,6 +118,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
shader.insert(pos, "#define TARGET_METAL_ENVIRONMENT\n");
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
} else if (backend == Backend::WEBGPU) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
}
|
||||
|
||||
const char* shaderCString = shader.c_str();
|
||||
@@ -150,7 +155,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
|
||||
assert_invariant(backend == Backend::OPENGL ||
|
||||
backend == Backend::METAL ||
|
||||
backend == Backend::VULKAN);
|
||||
backend == Backend::VULKAN ||
|
||||
backend == Backend::WEBGPU);
|
||||
|
||||
if (backend == Backend::OPENGL) {
|
||||
if (isMobile) {
|
||||
@@ -166,6 +172,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
|
||||
} else if (backend == Backend::WEBGPU){
|
||||
filamat::GLSLPostProcessor::spirvToWgsl(&spirv, &result);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
+110
-141
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "Lifetimes.h"
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
@@ -195,6 +196,8 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
|
||||
TEST_F(BackendTest, ColorMagnify) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -205,30 +208,30 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = api.createTexture(
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = api.createTexture(
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Do a "magnify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
@@ -238,16 +241,18 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMagnify.png" };
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
@@ -258,18 +263,12 @@ TEST_F(BackendTest, ColorMagnify) {
|
||||
const uint32_t expected = 0x410bdd31;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
for (auto rt : dstRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, ColorMinify) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -280,30 +279,30 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> const srcTexture = api.createTexture(
|
||||
Handle<HwTexture> const srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> const dstTexture = api.createTexture(
|
||||
Handle<HwTexture> const dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
dstRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
|
||||
@@ -314,6 +313,7 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
srcRenderTargets[srcLevel], {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel},
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMinify.png" };
|
||||
dumpScreenshot(api, dstRenderTargets[0], ¶ms);
|
||||
@@ -325,18 +325,11 @@ TEST_F(BackendTest, ColorMinify) {
|
||||
const uint32_t expected = 0xf3d9c53f;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
for (auto rt : dstRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, ColorResolve) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -356,40 +349,40 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
triangleVs, triangleFs, sBackend, sIsMobilePlatform, std::move(descriptors));
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
prog.descriptorBindings(1, {{ "Params", DescriptorType::UNIFORM_BUFFER, 0 }});
|
||||
program = api.createProgram(std::move(prog));
|
||||
program = cleanup.add(api.createProgram(std::move(prog)));
|
||||
}
|
||||
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = api.createDescriptorSetLayout({
|
||||
DescriptorSetLayoutHandle descriptorSetLayout = cleanup.add(api.createDescriptorSetLayout({
|
||||
{{
|
||||
DescriptorType::UNIFORM_BUFFER,
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, 0,
|
||||
DescriptorFlags::NONE, 0
|
||||
}}});
|
||||
}}}));
|
||||
|
||||
DescriptorSetHandle descriptorSet = api.createDescriptorSet(descriptorSetLayout);
|
||||
DescriptorSetHandle descriptorSet = cleanup.add(api.createDescriptorSet(descriptorSetLayout));
|
||||
|
||||
// Create a VertexBuffer, IndexBuffer, and RenderPrimitive.
|
||||
TrianglePrimitive const triangle(api);
|
||||
|
||||
// Create 4-sample texture.
|
||||
Handle<HwTexture> const srcColorTexture = api.createTexture(
|
||||
Handle<HwTexture> const srcColorTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create 1-sample texture.
|
||||
Handle<HwTexture> const dstColorTexture = api.createTexture(
|
||||
Handle<HwTexture> const dstColorTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create a 4-sample render target with the 4-sample texture.
|
||||
Handle<HwRenderTarget> const srcRenderTarget = api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const srcRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount, 0,
|
||||
{{ srcColorTexture }}, {}, {});
|
||||
{{ srcColorTexture }}, {}, {}));
|
||||
|
||||
// Create a 1-sample render target with the 1-sample texture.
|
||||
Handle<HwRenderTarget> const dstRenderTarget = api.createRenderTarget(
|
||||
Handle<HwRenderTarget> const dstRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, 0,
|
||||
{{ dstColorTexture }}, {}, {});
|
||||
{{ dstColorTexture }}, {}, {}));
|
||||
|
||||
// Prep for rendering.
|
||||
RenderPassParams params = {};
|
||||
@@ -408,8 +401,8 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
auto ubuffer = api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
auto ubuffer = cleanup.add(api.createBufferObject(sizeof(MaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
// Draw red triangle into srcRenderTarget.
|
||||
uploadUniforms(api, ubuffer, {
|
||||
.color = float4(1, 0, 0, 1),
|
||||
@@ -420,11 +413,12 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
||||
|
||||
// FIXME: on Metal this triangle is not drawn. Can't understand why.
|
||||
api.beginFrame(0, 0, 0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.beginRenderPass(srcRenderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
api.endFrame(0);
|
||||
}
|
||||
|
||||
// Resolve the MSAA render target into the single-sample render target.
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR,
|
||||
@@ -443,23 +437,15 @@ TEST_F(BackendTest, ColorResolve) {
|
||||
const uint32_t expected = 0xebfac2ef;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected);
|
||||
EXPECT_TRUE(sparams.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyDescriptorSet(descriptorSet);
|
||||
api.destroyDescriptorSetLayout(descriptorSetLayout);
|
||||
api.destroyBufferObject(ubuffer);
|
||||
api.destroyProgram(program);
|
||||
api.destroyTexture(srcColorTexture);
|
||||
api.destroyTexture(dstColorTexture);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
flushAndWait();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
api.startCapture(0);
|
||||
cleanup.addPostCall([&]() { api.stopCapture(0); });
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
constexpr int kSrcTexHeight = 256;
|
||||
@@ -474,27 +460,27 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
constexpr int kDstTexLayer = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D_ARRAY, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, kSrcTexDepth,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, kSrcTexLayer, float3(0.5, 0, 0), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = api.createTexture(
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Create two RenderTargets.
|
||||
const int level = 0;
|
||||
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {});
|
||||
Handle<HwRenderTarget> dstRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {});
|
||||
Handle<HwRenderTarget> srcRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {}));
|
||||
|
||||
// Do a blit from kSrcTexLayer of the source RT to kDstTexLayer of the destination RT.
|
||||
const int srcLevel = 0;
|
||||
@@ -503,16 +489,18 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
{0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "Blit2DTextureArray.png" };
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
@@ -523,20 +511,12 @@ TEST_F(BackendTest, Blit2DTextureArray) {
|
||||
const uint32_t expected = 0x8de7d55b;
|
||||
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
executeCommands();
|
||||
|
||||
api.stopCapture(0);
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, BlitRegion) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -549,21 +529,21 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
constexpr int kDstLevel = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
|
||||
// Create a destination texture.
|
||||
Handle<HwTexture> dstTexture = api.createTexture(
|
||||
Handle<HwTexture> dstTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kDstTexFormat, 1, kDstTexWidth, kDstTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
Viewport srcRect = {
|
||||
@@ -583,34 +563,34 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
// We purposely set the render target width and height to smaller than the texture, to check
|
||||
// that this case is handled correctly.
|
||||
Handle<HwRenderTarget> srcRenderTarget =
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {});
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
|
||||
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
Handle<HwRenderTarget> dstRenderTarget =
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {});
|
||||
cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
|
||||
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {}));
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
// Push through an empty frame to allow the texture to upload and the blit to execute.
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Grab a screenshot.
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegion.png" };
|
||||
api.beginFrame(0, 0, 0);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Check if the image matches perfectly to our golden run.
|
||||
//
|
||||
// TODO: for some reason, this test has very, very slight (as in one pixel) differences between
|
||||
// OpenGL and Metal. So disable golden checking for now.
|
||||
// Use the compare tool from ImageMagick to see visual differences:
|
||||
@@ -619,18 +599,12 @@ TEST_F(BackendTest, BlitRegion) {
|
||||
// const uint32_t expected = 0x74fa34ed;
|
||||
// printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", params.pixelHashResult, expected);
|
||||
// EXPECT_TRUE(params.pixelHashResult == expected);
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroyTexture(dstTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(srcRenderTarget);
|
||||
api.destroyRenderTarget(dstRenderTarget);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(getDriverApi());
|
||||
cleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
constexpr int kSrcTexHeight = 1024;
|
||||
@@ -640,14 +614,15 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = createSwapChain();
|
||||
Handle<HwRenderTarget> dstRenderTarget = api.createDefaultRenderTarget();
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Handle<HwRenderTarget> dstRenderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
|
||||
// Create a source texture.
|
||||
Handle<HwTexture> srcTexture = api.createTexture(
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(
|
||||
SamplerType::SAMPLER_2D, kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT);
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::UPLOADABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
const bool flipY = sBackend == Backend::OPENGL;
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 0, float3(0.5, 0, 0), flipY);
|
||||
createBitmap(api, srcTexture, kSrcTexWidth, kSrcTexHeight, 1, float3(0, 0, 0.5), flipY);
|
||||
@@ -655,8 +630,8 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
// Create a RenderTarget for each texture's miplevel.
|
||||
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
|
||||
for (uint8_t level = 0; level < kNumLevels; level++) {
|
||||
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
|
||||
srcRenderTargets[level] = cleanup.add(api.createRenderTarget( TargetBufferFlags::COLOR,
|
||||
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {}));
|
||||
}
|
||||
|
||||
// Blit one-quarter of src level 1 to dst level 0.
|
||||
@@ -674,29 +649,23 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
|
||||
.height = kDstTexHeight - 10,
|
||||
};
|
||||
|
||||
api.beginFrame(0, 0, 0);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
|
||||
dstRect, srcRenderTargets[srcLevel],
|
||||
srcRect, SamplerMagFilter::LINEAR);
|
||||
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
ScreenshotParams params { kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain.png" };
|
||||
dumpScreenshot(api, dstRenderTarget, ¶ms);
|
||||
|
||||
api.commit(swapChain);
|
||||
|
||||
api.endFrame(0);
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
// Cleanup.
|
||||
api.destroyTexture(srcTexture);
|
||||
api.destroySwapChain(swapChain);
|
||||
for (auto rt : srcRenderTargets) api.destroyRenderTarget(rt);
|
||||
executeCommands();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -62,6 +62,8 @@ constexpr std::pair<ChunkType, ChunkType> shaderLanguageToTags(ShaderLanguage co
|
||||
return { MaterialEssl1, DictionaryText };
|
||||
case ShaderLanguage::MSL:
|
||||
return { MaterialMetal, DictionaryText };
|
||||
case ShaderLanguage::WGSL:
|
||||
return { MaterialWgsl, DictionaryText };
|
||||
case ShaderLanguage::SPIRV:
|
||||
return { MaterialSpirv, DictionarySpirv };
|
||||
case ShaderLanguage::METAL_LIBRARY:
|
||||
|
||||
@@ -388,12 +388,13 @@ void FMaterial::terminate(FEngine& engine) {
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
} else {
|
||||
utils::slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
if (UTILS_UNLIKELY(!pos->second.empty())) {
|
||||
slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive." << io::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Unregister the material with matdbg.
|
||||
matdbg::DebugServer* server = engine.debug.server;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.58.1"
|
||||
spec.version = "1.58.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.1/filament-v1.58.1-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.0/filament-v1.58.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -52,6 +52,10 @@ include_directories(${PUBLIC_HDR_DIR})
|
||||
# we're building a library
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
if(FILAMENT_SUPPORTS_OSMESA)
|
||||
target_compile_options(${TARGET} PRIVATE -I${FILAMENT_OSMESA_PATH}/include/GL)
|
||||
endif()
|
||||
|
||||
# specify where the public headers of this library are
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
|
||||
@@ -14,16 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmesa.h>
|
||||
|
||||
namespace bluegl {
|
||||
|
||||
namespace {
|
||||
using ProcAddressFunc = void*(*)(char const* funcName);
|
||||
}
|
||||
|
||||
// This is to ensure that linking during compilation will not fail even if
|
||||
// OSMesaGetProcAddress is not linked.
|
||||
__attribute__((weak)) OSMESAproc OSMesaGetProcAddress(char const*);
|
||||
|
||||
struct Driver {
|
||||
ProcAddressFunc OSMesaGetProcAddress;
|
||||
void* library;
|
||||
@@ -31,7 +36,7 @@ struct Driver {
|
||||
|
||||
bool initBinder() {
|
||||
constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"};
|
||||
for (char const* name : libraryNames) {
|
||||
for (char const* name: libraryNames) {
|
||||
g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
|
||||
if (g_driver.library) {
|
||||
break;
|
||||
@@ -45,6 +50,10 @@ bool initBinder() {
|
||||
(ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
}
|
||||
|
||||
if (!g_driver.OSMesaGetProcAddress) {
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
return g_driver.OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ class FrameGraphTable extends LitElement {
|
||||
super();
|
||||
this.frameGraphData = null;
|
||||
this.selectedResourceId = -1;
|
||||
this.collapsedResources = new Set();
|
||||
this.expandedResourceSet = new Set();
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
@@ -365,11 +365,11 @@ class FrameGraphTable extends LitElement {
|
||||
}
|
||||
|
||||
_toggleCollapse(resourceIndex) {
|
||||
if (this.collapsedResources.has(resourceIndex)) {
|
||||
this.collapsedResources.delete(resourceIndex);
|
||||
if (this.expandedResourceSet.has(resourceIndex)) {
|
||||
this.expandedResourceSet.delete(resourceIndex);
|
||||
}
|
||||
else {
|
||||
this.collapsedResources.add(resourceIndex);
|
||||
this.expandedResourceSet.add(resourceIndex);
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
@@ -430,9 +430,9 @@ class FrameGraphTable extends LitElement {
|
||||
.map(subresource => subresource.id);
|
||||
|
||||
const hasSubresources = subresourceIds.length > 0;
|
||||
const isCollapsed = this.collapsedResources.has(resourceIndex);
|
||||
const isExpanded = this.expandedResourceSet.has(resourceIndex);
|
||||
// Show the aggregated resource usage when the subresources are collapsed.
|
||||
const resourceIds = isCollapsed ? [resource.id, ...subresourceIds]:[resource.id];
|
||||
const resourceIds = isExpanded ? [resource.id]:[resource.id, ...subresourceIds];
|
||||
|
||||
const onClickResource = () => this._handleResourceClick(resource.id);
|
||||
const selectedStyle = resource.id === this.selectedResourceId ? "selected" : "";
|
||||
@@ -444,15 +444,15 @@ class FrameGraphTable extends LitElement {
|
||||
? html`
|
||||
<span class="toggle-icon"
|
||||
@click="${(e) => { e.stopPropagation(); this._toggleCollapse(resourceIndex); }}">
|
||||
${isCollapsed ? '▶' : '▼'}
|
||||
${isExpanded ? '▼' : '▶'}
|
||||
</span>`
|
||||
: nothing}
|
||||
${resource.name}
|
||||
${hasSubresources && isCollapsed ? html`(${subresourceIds.length})` : nothing}
|
||||
${hasSubresources && isExpanded ? nothing : html`(${subresourceIds.length})`}
|
||||
</th>
|
||||
${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)}
|
||||
</tr>
|
||||
${!isCollapsed ? this._renderSubresourceRows(resources, resource, resourceIndex, allPasses) : nothing}
|
||||
${isExpanded ? this._renderSubresourceRows(resources, resource, resourceIndex, allPasses) : nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialEssl1 = charTo64bitNum("MAT_ESS1"),
|
||||
MaterialSpirv = charTo64bitNum("MAT_SPIR"),
|
||||
MaterialMetal = charTo64bitNum("MAT_METL"),
|
||||
MaterialWgsl = charTo64bitNum("MAT_WGSL"),
|
||||
MaterialMetalLibrary = charTo64bitNum("MAT_MLIB"),
|
||||
MaterialShaderModels = charTo64bitNum("MAT_SMDL"),
|
||||
MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"),
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 58;
|
||||
static constexpr size_t MATERIAL_VERSION = 57;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -183,6 +183,7 @@ bool MaterialChunk::getShader(ShaderContent& shaderContent, BlobDictionary const
|
||||
switch (mMaterialTag) {
|
||||
case filamat::ChunkType::MaterialGlsl:
|
||||
case filamat::ChunkType::MaterialEssl1:
|
||||
case filamat::ChunkType::MaterialWgsl:
|
||||
case filamat::ChunkType::MaterialMetal:
|
||||
return getTextShader(mUnflattener, dictionary, shaderContent, shaderModel, variant, stage);
|
||||
case filamat::ChunkType::MaterialSpirv:
|
||||
|
||||
@@ -81,7 +81,11 @@ public:
|
||||
VULKAN = 0x02u,
|
||||
METAL = 0x04u,
|
||||
WEBGPU = 0x08u,
|
||||
#ifdef FILAMENT_SUPPORTS_WEBGPU
|
||||
ALL = OPENGL | VULKAN | METAL | WEBGPU
|
||||
#else
|
||||
ALL = OPENGL | VULKAN | METAL
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -527,11 +527,14 @@ bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl)
|
||||
tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts);
|
||||
|
||||
if (tintRead.Diagnostics().ContainsErrors()) {
|
||||
slog.w << "This tint reader error is currently ignored during WebGPU bringup:" << tintRead.Diagnostics().Str() << io::endl;
|
||||
|
||||
//TODO: We should actually return false here, but for initial debugging
|
||||
// let it slide until combined image sampler is resolved
|
||||
// return false;
|
||||
//TODO remove this if block once combined image sampler conversion works.
|
||||
if (tintRead.Diagnostics().Str().rfind("error: WGSL does not support combined image-samplers") != std::string::npos) {
|
||||
slog.w << "This tint reader error is currently ignored during WebGPU bringup: " << tintRead.Diagnostics().Str() << io::endl;
|
||||
}
|
||||
else {
|
||||
slog.e << "Tint Reader Error: " << tintRead.Diagnostics().Str() << io::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tint::Result<tint::wgsl::writer::Output> wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts);
|
||||
@@ -539,10 +542,8 @@ bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl)
|
||||
tint::SuccessType tintSuccess;
|
||||
|
||||
if (wgslOut != tintSuccess) {
|
||||
slog.w << "This tint writer error is currently ignored during WebGPU bringup:" << wgslOut.Failure().reason.Str() << io::endl;
|
||||
//TODO: We should actually return false here, but for initial debugging
|
||||
// let it slide until combined image sampler is resolved
|
||||
// return false;
|
||||
slog.e << "Tint writer error: " << wgslOut.Failure().reason.Str() << io::endl;
|
||||
return false;
|
||||
}
|
||||
*outWsl = wgslOut->wgsl;
|
||||
return true;
|
||||
|
||||
@@ -179,6 +179,14 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics,
|
||||
effectiveFeatureLevel,
|
||||
});
|
||||
}
|
||||
if (any(mTargetApi & TargetApi::WEBGPU)) {
|
||||
mCodeGenPermutations.push_back({
|
||||
shaderModel,
|
||||
TargetApi::WEBGPU,
|
||||
TargetLanguage::SPIRV,
|
||||
effectiveFeatureLevel,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,6 +844,7 @@ static void showErrorMessage(const char* materialName, filament::Variant variant
|
||||
break;
|
||||
case TargetApi::WEBGPU:
|
||||
targetApiString = "WebGPU.\n";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
assert(0); // Unreachable.
|
||||
break;
|
||||
@@ -879,6 +888,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
std::vector<TextEntry> essl1Entries;
|
||||
std::vector<BinaryEntry> spirvEntries;
|
||||
std::vector<TextEntry> metalEntries;
|
||||
std::vector<TextEntry> wgslEntries;
|
||||
LineDictionary textDictionary;
|
||||
BlobDictionary spirvDictionary;
|
||||
// End: must be protected by lock
|
||||
@@ -907,7 +917,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
|
||||
// Metal Shading Language is cross-compiled from Vulkan.
|
||||
const bool targetApiNeedsSpirv =
|
||||
(targetApi == TargetApi::VULKAN || targetApi == TargetApi::METAL);
|
||||
(targetApi == TargetApi::VULKAN || targetApi == TargetApi::METAL || targetApi == TargetApi::WEBGPU);
|
||||
const bool targetApiNeedsMsl = targetApi == TargetApi::METAL;
|
||||
const bool targetApiNeedsWgsl = targetApi == TargetApi::WEBGPU;
|
||||
const bool targetApiNeedsGlsl = targetApi == TargetApi::OPENGL;
|
||||
@@ -933,14 +943,17 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
TextEntry glslEntry{};
|
||||
BinaryEntry spirvEntry{};
|
||||
TextEntry metalEntry{};
|
||||
TextEntry wgslEntry{};
|
||||
|
||||
glslEntry.shaderModel = params.shaderModel;
|
||||
spirvEntry.shaderModel = params.shaderModel;
|
||||
metalEntry.shaderModel = params.shaderModel;
|
||||
wgslEntry.shaderModel = params.shaderModel;
|
||||
|
||||
glslEntry.variant = v.variant;
|
||||
spirvEntry.variant = v.variant;
|
||||
metalEntry.variant = v.variant;
|
||||
wgslEntry.variant = v.variant;
|
||||
|
||||
// Generate raw shader code.
|
||||
// The quotes in Google-style line directives cause problems with certain drivers. These
|
||||
@@ -1038,6 +1051,12 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
switch (targetApi) {
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
assert(!spirv.empty());
|
||||
assert(wgsl.length() > 0);
|
||||
wgslEntry.stage = v.stage;
|
||||
wgslEntry.shader = wgsl;
|
||||
wgslEntries.push_back(wgslEntry);
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// should never happen
|
||||
break;
|
||||
@@ -1099,6 +1118,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
std::sort(essl1Entries.begin(), essl1Entries.end(), compare);
|
||||
std::sort(spirvEntries.begin(), spirvEntries.end(), compare);
|
||||
std::sort(metalEntries.begin(), metalEntries.end(), compare);
|
||||
std::sort(wgslEntries.begin(), wgslEntries.end(), compare);
|
||||
|
||||
// Generate the dictionaries.
|
||||
for (const auto& s : glslEntries) {
|
||||
@@ -1114,6 +1134,9 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
for (const auto& s : metalEntries) {
|
||||
textDictionary.addText(s.shader);
|
||||
}
|
||||
for (const auto& s : wgslEntries) {
|
||||
textDictionary.addText(s.shader);
|
||||
}
|
||||
|
||||
// Emit dictionary chunk (TextDictionaryReader and DictionaryTextChunk)
|
||||
const auto& dictionaryChunk = container.push<filamat::DictionaryTextChunk>(
|
||||
@@ -1144,6 +1167,12 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
dictionaryChunk.getDictionary(), ChunkType::MaterialMetal);
|
||||
}
|
||||
|
||||
// Emit WGSL chunk (MaterialTextChunk).
|
||||
if (!wgslEntries.empty()) {
|
||||
container.push<MaterialTextChunk>(std::move(wgslEntries),
|
||||
dictionaryChunk.getDictionary(), ChunkType::MaterialWgsl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -525,6 +525,11 @@ EShMessages GLSLTools::glslangFlagsFromTargetApi(
|
||||
// choke on gl_VertexIndex.
|
||||
msg |= (Type)EShMessages::EShMsgVulkanRules;
|
||||
}
|
||||
if (targetApi == TargetApi::WEBGPU) {
|
||||
// FIXME: We have to use EShMsgVulkanRules for WEBGPU, otherwise compilation will
|
||||
// choke on gl_VertexIndex.
|
||||
msg |= (Type)EShMessages::EShMsgVulkanRules;
|
||||
}
|
||||
return (EShMessages)msg;
|
||||
}
|
||||
}
|
||||
@@ -540,13 +545,13 @@ void GLSLTools::prepareShaderParser(MaterialBuilder::TargetApi targetApi,
|
||||
shader.setEnvInput(EShSourceGlsl, stage, EShClientOpenGL, version);
|
||||
shader.setEnvClient(EShClientOpenGL, EShTargetOpenGL_450);
|
||||
break;
|
||||
case MaterialBuilderBase::TargetApi::WEBGPU:
|
||||
case MaterialBuilderBase::TargetApi::VULKAN:
|
||||
case MaterialBuilderBase::TargetApi::METAL:
|
||||
shader.setEnvInput(EShSourceGlsl, stage, EShClientVulkan, version);
|
||||
shader.setEnvClient(EShClientVulkan, EShTargetVulkan_1_1);
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case MaterialBuilderBase::TargetApi::WEBGPU:
|
||||
case MaterialBuilderBase::TargetApi::ALL:
|
||||
// can't happen
|
||||
break;
|
||||
|
||||
@@ -175,6 +175,10 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
//For now, no differences so inherit the same changes.
|
||||
// TODO Define a separte environment, OR relevant checks
|
||||
out << "#define TARGET_VULKAN_ENVIRONMENT\n";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// invalid should never happen
|
||||
break;
|
||||
@@ -190,6 +194,7 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
}
|
||||
|
||||
if (mTargetApi == TargetApi::VULKAN ||
|
||||
mTargetApi == TargetApi::WEBGPU ||
|
||||
mTargetApi == TargetApi::METAL ||
|
||||
(mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::DESKTOP) ||
|
||||
mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_2) {
|
||||
@@ -725,6 +730,8 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
out << "set = " << +set << ", binding = " << +binding << ", ";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// nonsensical, shouldn't happen.
|
||||
break;
|
||||
@@ -813,6 +820,8 @@ io::sstream& CodeGenerator::generateCommonSamplers(utils::io::sstream& out,
|
||||
break;
|
||||
// TODO: Handle webgpu here
|
||||
case TargetApi::WEBGPU:
|
||||
out << "layout(binding = " << +info.binding << ", set = " << +set << ") ";
|
||||
break;
|
||||
case TargetApi::ALL:
|
||||
// should not happen
|
||||
break;
|
||||
|
||||
@@ -891,7 +891,78 @@ TEST_F(MaterialCompiler, FeatureLevel0Ess3CallFails) {
|
||||
EXPECT_FALSE(result.isValid());
|
||||
}
|
||||
|
||||
#if FILAMENT_SUPPORTS_WEBGPU
|
||||
TEST_F(MaterialCompiler, WgslConversionBakedColor) {
|
||||
std::string bakedColorCodeFrag(R"(
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = getColor();
|
||||
}
|
||||
)");
|
||||
filamat::MaterialBuilder builder;
|
||||
builder.targetApi(filamat::MaterialBuilderBase::TargetApi::WEBGPU);
|
||||
builder.material(bakedColorCodeFrag.c_str());
|
||||
builder.shading(filamat::MaterialBuilder::Shading::UNLIT);
|
||||
builder.name("BakedColor");
|
||||
builder.culling(CullingMode::NONE);
|
||||
builder.featureLevel(FeatureLevel::FEATURE_LEVEL_0);
|
||||
builder.require(filament::VertexAttribute::COLOR);
|
||||
builder.variantFilter(static_cast<filament::UserVariantFilterMask>(
|
||||
filament::UserVariantFilterBit::SKINNING | filament::UserVariantFilterBit::STE));
|
||||
filamat::Package result = builder.build(*jobSystem);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
|
||||
TEST_F(MaterialCompiler, WgslConversionSandboxLitTransparent) {
|
||||
std::string litTransparentCodeFrag(R"(
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor.rgb = materialParams.baseColor * materialParams.alpha;
|
||||
material.baseColor.a = materialParams.alpha;
|
||||
material.roughness = materialParams.roughness;
|
||||
material.metallic = materialParams.metallic;
|
||||
material.reflectance = materialParams.reflectance;
|
||||
material.sheenColor = materialParams.sheenColor;
|
||||
material.sheenRoughness = materialParams.sheenRoughness;
|
||||
material.clearCoat = materialParams.clearCoat;
|
||||
material.clearCoatRoughness = materialParams.clearCoatRoughness;
|
||||
material.anisotropy = materialParams.anisotropy;
|
||||
material.emissive = materialParams.emissive;
|
||||
}
|
||||
)");
|
||||
filamat::MaterialBuilder builder;
|
||||
builder.targetApi(filamat::MaterialBuilderBase::TargetApi::WEBGPU);
|
||||
builder.material(litTransparentCodeFrag.c_str());
|
||||
builder.shading(filamat::MaterialBuilder::Shading::LIT);
|
||||
builder.name("LitTransparent");
|
||||
builder.blending(filament::BlendingMode::TRANSPARENT);
|
||||
builder.specularAntiAliasing(true);
|
||||
|
||||
builder.parameter("alpha", 1, UniformType::FLOAT);
|
||||
builder.parameter("baseColor", 1, UniformType::FLOAT3);
|
||||
builder.parameter("roughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("metallic", 1, UniformType::FLOAT);
|
||||
builder.parameter("reflectance", 1, UniformType::FLOAT);
|
||||
builder.parameter("sheenColor", 1, UniformType::FLOAT3);
|
||||
builder.parameter("sheenRoughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("clearCoat", 1, UniformType::FLOAT);
|
||||
builder.parameter("clearCoatRoughness", 1, UniformType::FLOAT);
|
||||
builder.parameter("anisotropy", 1, UniformType::FLOAT);
|
||||
builder.parameter("emissive", 1, UniformType::FLOAT4);
|
||||
|
||||
builder.variantFilter(static_cast<filament::UserVariantFilterMask>(
|
||||
filament::UserVariantFilterBit::SKINNING | filament::UserVariantFilterBit::STE));
|
||||
filamat::Package result = builder.build(*jobSystem);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
const int rv = RUN_ALL_TESTS();
|
||||
if (testing::UnitTest::GetInstance()->test_to_run_count() == 0) {
|
||||
//If you run a test filter that contains 0 tests that was likely not intentional. Fail in that scenario.
|
||||
return 1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,10 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
json << "metal";
|
||||
chunkType = ChunkType::MaterialMetal;
|
||||
break;
|
||||
case ShaderLanguage::WGSL:
|
||||
json << "webgpu";
|
||||
chunkType = ChunkType::MaterialWgsl;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ ShaderExtractor::ShaderExtractor(backend::ShaderLanguage target, const void* dat
|
||||
mMaterialTag = ChunkType::MaterialMetalLibrary;
|
||||
mDictionaryTag = ChunkType::DictionaryMetalLibrary;
|
||||
break;
|
||||
case backend::ShaderLanguage::WGSL:
|
||||
mMaterialTag = ChunkType::MaterialWgsl;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::SPIRV:
|
||||
mMaterialTag = ChunkType::MaterialSpirv;
|
||||
mDictionaryTag = ChunkType::DictionarySpirv;
|
||||
|
||||
@@ -135,6 +135,10 @@ ShaderReplacer::ShaderReplacer(Backend backend, ShaderLanguage language,
|
||||
mMaterialTag = ChunkType::MaterialMetal;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::WGSL:
|
||||
mMaterialTag = ChunkType::MaterialWgsl;
|
||||
mDictionaryTag = ChunkType::DictionaryText;
|
||||
break;
|
||||
case backend::ShaderLanguage::SPIRV:
|
||||
mMaterialTag = ChunkType::MaterialSpirv;
|
||||
mDictionaryTag = ChunkType::DictionarySpirv;
|
||||
|
||||
@@ -429,7 +429,10 @@ static bool printShaderInfo(ostream& text, const ChunkContainer& container, Chun
|
||||
break;
|
||||
case ChunkType::MaterialMetalLibrary:
|
||||
text << "Metal precompiled shader libraries:" << endl;
|
||||
break;
|
||||
break;
|
||||
case ChunkType::MaterialWgsl:
|
||||
text << "WGSL precompiled shader libraries:" << endl;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Invalid shader ChunkType");
|
||||
break;
|
||||
@@ -467,6 +470,9 @@ bool TextWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) {
|
||||
if (!printShaderInfo(text, container, ChunkType::MaterialMetalLibrary)) {
|
||||
return false;
|
||||
}
|
||||
if (!printShaderInfo(text, container, ChunkType::MaterialWgsl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printChunks(text, container);
|
||||
|
||||
|
||||
@@ -35,10 +35,13 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
else
|
||||
set +e
|
||||
apt-get -y build-dep mesa
|
||||
sudo apt -y remove llvm-18 llvm-18-*
|
||||
sudo apt-get -y build-dep mesa
|
||||
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
|
||||
set -e
|
||||
|
||||
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
|
||||
GITHUB_CLANG_VERSION=${GITHUB_CLANG_VERSION:-${CURRENT_CLANG_VERSION}}
|
||||
|
||||
sudo apt-get -y install clang-${GITHUB_CLANG_VERSION} \
|
||||
libc++-${GITHUB_CLANG_VERSION}-dev \
|
||||
libc++abi-${GITHUB_CLANG_VERSION}-dev \
|
||||
|
||||
@@ -262,6 +262,8 @@ bool CommandlineConfig::parse() {
|
||||
mTargetApi |= TargetApi::VULKAN;
|
||||
} else if (arg == "metal") {
|
||||
mTargetApi |= TargetApi::METAL;
|
||||
} else if (arg == "webgpu") {
|
||||
mTargetApi |= TargetApi::WEBGPU;
|
||||
} else if (arg == "all") {
|
||||
mTargetApi |= TargetApi::ALL;
|
||||
} else {
|
||||
|
||||
@@ -532,7 +532,7 @@ static bool parseChunks(Config config, void* data, size_t size) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO Include a printWgsl logic here
|
||||
if (config.printMetal) {
|
||||
const filament::backend::ShaderLanguage language = config.binary
|
||||
? filament::backend::ShaderLanguage::METAL_LIBRARY
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.58.1",
|
||||
"version": "1.58.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user