webgpu: enable choosing vulkan backend on MacOS (#9106)
- Add a Configuration struct to the WebGPUPlatform class. This allows for client-side setting of WebGPU backend configurations. - Add a configuration for forcing the wgpu backend to pick a certain backend. - Add Vulkan as a potential backend for WebGPU + MacOS. - Locally modify Dawn so that it does not assume only switfshader is available for Vulkan on MacOS. - Enable vulkan support for Dawn (third_party/dawn/tnt/CMakeLists.txt) - Plumb option to pick different WebGPU backend through FilamentApp and gltf_viewer.
This commit is contained in:
@@ -30,7 +30,7 @@ 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 {
|
||||
class WebGPUPlatform : public Platform {
|
||||
public:
|
||||
WebGPUPlatform();
|
||||
~WebGPUPlatform() override = default;
|
||||
@@ -52,6 +52,14 @@ public:
|
||||
// either returns a valid device or panics
|
||||
[[nodiscard]] wgpu::Device requestDevice(wgpu::Adapter const& adapter);
|
||||
|
||||
struct Configuration {
|
||||
wgpu::BackendType forceBackendType = wgpu::BackendType::Undefined;
|
||||
};
|
||||
|
||||
[[nodiscard]] virtual Configuration getConfiguration() const noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Driver* createDriver(void* sharedContext,
|
||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
|
||||
@@ -505,6 +505,7 @@ struct AdapterDetailsHash final {
|
||||
|
||||
// selects one preferred adapter or panics if none can be found
|
||||
wgpu::Adapter selectPreferredAdapter(
|
||||
WebGPUPlatform::Configuration const& configuration,
|
||||
std::unordered_set<AdapterDetails, AdapterDetailsHash> const& compatibleAdapters) {
|
||||
// for each unique adapter...
|
||||
AdapterDetails const* selectedAdapter = nullptr;
|
||||
@@ -512,6 +513,10 @@ wgpu::Adapter selectPreferredAdapter(
|
||||
|
||||
// choose the most desirable adapter that meets the minimum requirements...
|
||||
for (AdapterDetails const& details: compatibleAdapters) {
|
||||
if (configuration.forceBackendType != wgpu::BackendType::Undefined &&
|
||||
configuration.forceBackendType != details.info.backendType) {
|
||||
continue;
|
||||
}
|
||||
if (!adapterMeetsMinimumRequirements(details)) {
|
||||
continue;
|
||||
}
|
||||
@@ -587,7 +592,7 @@ wgpu::Adapter WebGPUPlatform::requestAdapter(wgpu::Surface const& surface) {
|
||||
}
|
||||
const std::unordered_set<AdapterDetails, AdapterDetailsHash> compatibleAdapters =
|
||||
requestCompatibleAdapters(mInstance, requests);
|
||||
return selectPreferredAdapter(compatibleAdapters);
|
||||
return selectPreferredAdapter(getConfiguration(), compatibleAdapters);
|
||||
}
|
||||
|
||||
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||
|
||||
@@ -38,7 +38,12 @@ std::vector<wgpu::RequestAdapterOptions> WebGPUPlatform::getAdapterOptions() {
|
||||
constexpr std::array powerPreferences = {
|
||||
wgpu::PowerPreference::HighPerformance,
|
||||
wgpu::PowerPreference::LowPower };
|
||||
constexpr std::array backendTypes = { wgpu::BackendType::Metal };
|
||||
constexpr std::array backendTypes = {
|
||||
wgpu::BackendType::Metal,
|
||||
// To enable software rasterization on MacOS, we need to ensure Vulkan adapters are
|
||||
// available.
|
||||
wgpu::BackendType::Vulkan,
|
||||
};
|
||||
constexpr std::array forceFallbackAdapters = { false, true };
|
||||
constexpr size_t totalCombinations =
|
||||
powerPreferences.size() * backendTypes.size() * forceFallbackAdapters.size();
|
||||
|
||||
@@ -141,6 +141,10 @@ include_directories(${PUBLIC_HDR_DIR})
|
||||
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
target_link_libraries(${TARGET} PRIVATE dawncpp_headers)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET} PUBLIC ${LIBS} filamentapp-resources)
|
||||
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
|
||||
@@ -37,8 +37,15 @@ struct Config {
|
||||
int stereoscopicEyeCount = 2;
|
||||
uint8_t samples = 1;
|
||||
|
||||
// Provided to indicate GPU preference for vulkan
|
||||
// Indicate GPU preference for vulkan
|
||||
std::string vulkanGPUHint;
|
||||
|
||||
|
||||
// Note that WebGPU has its own enums for backends, but to avoid leaking webgpu headers to
|
||||
// consumers of FilamentApp, we just overload the Engine::Backend enum.
|
||||
using WebGPUBackend = filament::Engine::Backend;
|
||||
// Force a backend for webgpu.
|
||||
WebGPUBackend forcedWebGPUBackend = WebGPUBackend::DEFAULT;
|
||||
};
|
||||
|
||||
#endif // TNT_FILAMENT_SAMPLE_CONFIG_H
|
||||
|
||||
@@ -49,13 +49,18 @@ class ImGuiHelper;
|
||||
class IBL;
|
||||
class MeshAssimp;
|
||||
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
// For customizing the vulkan backend
|
||||
namespace filament::backend {
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
class VulkanPlatform;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
class WebGPUPlatform;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
class FilamentApp {
|
||||
public:
|
||||
using SetupCallback = std::function<void(filament::Engine*, filament::View*, filament::Scene*)>;
|
||||
@@ -261,6 +266,11 @@ private:
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
filament::backend::VulkanPlatform* mVulkanPlatform = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
filament::backend::WebGPUPlatform* mWebGPUPlatform = nullptr;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // TNT_FILAMENT_SAMPLE_FILAMENTAPP_H
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
@@ -27,6 +26,7 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#include <utils/EntityManager.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Path.h>
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
#endif
|
||||
|
||||
#include <filagui/ImGuiHelper.h>
|
||||
|
||||
#include <filamentapp/Cube.h>
|
||||
@@ -103,6 +107,36 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
class FilamentAppWebGPUPlatform : public WebGPUPlatform {
|
||||
public:
|
||||
FilamentAppWebGPUPlatform(Config::WebGPUBackend backend)
|
||||
: mBackend(backend) {}
|
||||
|
||||
virtual WebGPUPlatform::Configuration getConfiguration() const noexcept override {
|
||||
WebGPUPlatform::Configuration config = {};
|
||||
switch (mBackend) {
|
||||
case Config::WebGPUBackend::VULKAN:
|
||||
config.forceBackendType = wgpu::BackendType::Vulkan;
|
||||
break;
|
||||
case Config::WebGPUBackend::METAL:
|
||||
config.forceBackendType = wgpu::BackendType::Metal;
|
||||
break;
|
||||
case Config::WebGPUBackend::DEFAULT:
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "FilamentApp: Unsupported webgpu backend was selected(="
|
||||
<< (int) mBackend << "). Selection is ignored.";
|
||||
break;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
private:
|
||||
Config::WebGPUBackend const mBackend;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FilamentApp& FilamentApp::get() {
|
||||
@@ -532,6 +566,13 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback,
|
||||
delete mVulkanPlatform;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
if (mWebGPUPlatform) {
|
||||
delete mWebGPUPlatform;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// RELATIVE_ASSET_PATH is set inside samples/CMakeLists.txt and used to support multi-configuration
|
||||
@@ -662,21 +703,25 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
|
||||
engineConfig.stereoscopicType = Engine::StereoscopicType::NONE;
|
||||
#endif
|
||||
|
||||
Platform* platform = nullptr;
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
if (backend == Engine::Backend::VULKAN) {
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
mFilamentApp->mVulkanPlatform =
|
||||
new FilamentAppVulkanPlatform(config.vulkanGPUHint.c_str());
|
||||
return Engine::Builder()
|
||||
.backend(backend)
|
||||
.platform(mFilamentApp->mVulkanPlatform)
|
||||
.featureLevel(config.featureLevel)
|
||||
.config(&engineConfig)
|
||||
.build();
|
||||
#endif
|
||||
platform = mFilamentApp->mVulkanPlatform =
|
||||
new FilamentAppVulkanPlatform(config.vulkanGPUHint.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FILAMENT_SUPPORTS_WEBGPU)
|
||||
if (backend == Engine::Backend::WEBGPU) {
|
||||
platform = mFilamentApp->mWebGPUPlatform =
|
||||
new FilamentAppWebGPUPlatform(config.forcedWebGPUBackend);
|
||||
}
|
||||
#endif
|
||||
|
||||
return Engine::Builder()
|
||||
.backend(backend)
|
||||
.featureLevel(config.featureLevel)
|
||||
.platform(platform)
|
||||
.config(&engineConfig)
|
||||
.build();
|
||||
};
|
||||
|
||||
@@ -196,7 +196,9 @@ static void printUsage(char* name) {
|
||||
" a substring to match against the device name\n\n"
|
||||
" --screenshot-as-ppm, -d\n"
|
||||
" export PPM as oppose to TIFF screenshots\n\n"
|
||||
|
||||
" --webgpu-backend=<backend>, -w\n"
|
||||
" You can force WebGPU to select a backend of your choice. Provided that the platform\n"
|
||||
" supports this backend. (See -a for argument options).\n\n"
|
||||
);
|
||||
const std::string from("SHOWCASE");
|
||||
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
|
||||
@@ -215,7 +217,7 @@ static std::ifstream::pos_type getFileSize(const char* filename) {
|
||||
}
|
||||
|
||||
static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
static constexpr const char* OPTSTR = "ha:f:i:usc:rt:b:evg:d";
|
||||
static constexpr const char* OPTSTR = "ha:f:i:usc:rt:b:evg:dw:";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
@@ -232,6 +234,7 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
{ "split-view", no_argument, nullptr, 'v' },
|
||||
{ "vulkan-gpu-hint", required_argument, nullptr, 'g' },
|
||||
{ "screenshot-as-ppm", no_argument, nullptr, 'd' },
|
||||
{ "webgpu-backend", required_argument, nullptr, 'w' },
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
int opt;
|
||||
@@ -313,6 +316,10 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
||||
app->screenshotAsPPM = true;
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
app->config.forcedWebGPUBackend = samples::parseArgumentsForBackend(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (app->config.headless && app->batchFile.empty()) {
|
||||
|
||||
@@ -545,12 +545,6 @@ std::vector<Ref<PhysicalDeviceBase>> Backend::DiscoverPhysicalDevices(
|
||||
std::vector<Ref<PhysicalDeviceBase>> physicalDevices;
|
||||
InstanceBase* instance = GetInstance();
|
||||
for (ICD icd : kICDs) {
|
||||
#if DAWN_PLATFORM_IS(MACOS)
|
||||
// On Mac, we don't expect non-Swiftshader Vulkan to be available.
|
||||
if (icd == ICD::None) {
|
||||
continue;
|
||||
}
|
||||
#endif // DAWN_PLATFORM_IS(MACOS)
|
||||
if (options->forceFallbackAdapter && icd != ICD::SwiftShader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
1
third_party/dawn/tnt/CMakeLists.txt
vendored
1
third_party/dawn/tnt/CMakeLists.txt
vendored
@@ -15,6 +15,7 @@ set(DAWN_GLSLANG_DIR ${EXTERNAL}/glslang/)
|
||||
set(DAWN_DXC_ENABLE_ASSERTS_IN_NDEBUG OFF)
|
||||
set(DAWN_BUILD_MONOLITHIC_LIBRARY STATIC)
|
||||
set(TINT_BUILD_CMD_TOOLS OFF)
|
||||
set(DAWN_ENABLE_VULKAN ON)
|
||||
|
||||
if (FILAMENT_BUILD_FILAMAT)
|
||||
set(TINT_BUILD_SPV_READER ON)
|
||||
|
||||
3
third_party/dawn/tnt/README.md
vendored
3
third_party/dawn/tnt/README.md
vendored
@@ -18,6 +18,7 @@ cd ..
|
||||
rm -rf dawn
|
||||
mv dawn_copy dawn
|
||||
patch -p2 < dawn/tnt/dawn-generator-CMakeList.patch
|
||||
patch -p2 < dawn/tnt/remove-vk-macos-restriction.patch
|
||||
# remove redundant 3rd party dependencies with Filament itself
|
||||
rm -rf \
|
||||
dawn/third_party/abseil-cpp \
|
||||
@@ -36,4 +37,4 @@ version in the new Dawn commit.
|
||||
|
||||
Above steps are fragile and can cause compilation or functional breakage. Please be sure to test Filament before uploading your CL.
|
||||
Make sure to fix any new issues that are caused by this update. dawn/tnt/CMakeLists.txt may need to be edited for
|
||||
an update.
|
||||
an update.
|
||||
|
||||
17
third_party/dawn/tnt/remove-vk-macos-restriction.patch
vendored
Normal file
17
third_party/dawn/tnt/remove-vk-macos-restriction.patch
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
diff --git a/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp b/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
|
||||
index 4411af890..d0d9d3e26 100644
|
||||
--- a/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
|
||||
+++ b/third_party/dawn/src/dawn/native/vulkan/BackendVk.cpp
|
||||
@@ -545,12 +545,6 @@ std::vector<Ref<PhysicalDeviceBase>> Backend::DiscoverPhysicalDevices(
|
||||
std::vector<Ref<PhysicalDeviceBase>> physicalDevices;
|
||||
InstanceBase* instance = GetInstance();
|
||||
for (ICD icd : kICDs) {
|
||||
-#if DAWN_PLATFORM_IS(MACOS)
|
||||
- // On Mac, we don't expect non-Swiftshader Vulkan to be available.
|
||||
- if (icd == ICD::None) {
|
||||
- continue;
|
||||
- }
|
||||
-#endif // DAWN_PLATFORM_IS(MACOS)
|
||||
if (options->forceFallbackAdapter && icd != ICD::SwiftShader) {
|
||||
continue;
|
||||
}
|
||||
Reference in New Issue
Block a user