diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..eec3df3f3c 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,5 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut + +- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel` diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index e5bb4e95fa..72b499e618 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -483,6 +483,12 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu builder->config(&config); } +extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderFeatureLevel( + JNIEnv*, jclass, jlong nativeBuilder, jint ordinal) { + Engine::Builder* builder = (Engine::Builder*) nativeBuilder; + builder->featureLevel((Engine::FeatureLevel)ordinal); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderSharedContext( JNIEnv*, jclass, jlong nativeBuilder, jlong sharedContext) { Engine::Builder* builder = (Engine::Builder*) nativeBuilder; diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index 3423e87d05..43224036e3 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -209,6 +209,17 @@ public class Engine { return this; } + /** + * Sets the initial featureLevel for the Engine. + * + * @param featureLevel The feature level at which initialize Filament. + * @return A reference to this Builder for chaining calls. + */ + public Builder featureLevel(FeatureLevel featureLevel) { + nSetBuilderFeatureLevel(mNativeBuilder, featureLevel.ordinal()); + return this; + } + /** * Creates an instance of Engine * @@ -1149,6 +1160,7 @@ public class Engine { private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB, long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB, long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount); + private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal); private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext); private static native long nBuilderBuild(long nativeBuilder); } diff --git a/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt b/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt index 7d34a3031d..8571ee4d60 100644 --- a/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt +++ b/android/samples/sample-hello-triangle/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt @@ -110,7 +110,7 @@ class MainActivity : Activity() { } private fun setupFilament() { - engine = Engine.create() + engine = Engine.Builder().featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build() renderer = engine.createRenderer() scene = engine.createScene() view = engine.createView() @@ -120,13 +120,8 @@ class MainActivity : Activity() { private fun setupView() { scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine) - if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) { - // post-processing is not supported at feature level 0 - view.isPostProcessingEnabled = false - } else { - // NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference - // view.isPostProcessingEnabled = false - } + // post-processing is not supported at feature level 0 + view.isPostProcessingEnabled = false // Tell the view which camera we want to use view.camera = camera diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index b65e3cca9b..8eb45b40b5 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -218,6 +218,7 @@ set(MATERIAL_SRCS src/materials/colorGrading/customResolveAsSubpass.mat src/materials/debugShadowCascades.mat src/materials/defaultMaterial.mat + src/materials/defaultMaterial0.mat src/materials/dof/dof.mat src/materials/dof/dofCoc.mat src/materials/dof/dofDownsample.mat @@ -237,6 +238,7 @@ set(MATERIAL_SRCS src/materials/ssao/bilateralBlurBentNormals.mat src/materials/ssao/mipmapDepth.mat src/materials/skybox.mat + src/materials/skybox0.mat src/materials/ssao/sao.mat src/materials/ssao/saoBentNormals.mat src/materials/separableGaussianBlur.mat @@ -245,11 +247,6 @@ set(MATERIAL_SRCS src/materials/vsmMipmap.mat ) -set(MATERIAL_ES2_SRCS - src/materials/defaultMaterial0.mat - src/materials/skybox0.mat -) - # Embed the binary resource blob for materials. get_resgen_vars(${RESOURCE_DIR} materials) list(APPEND PRIVATE_HDRS ${RESGEN_HEADER}) @@ -315,23 +312,6 @@ foreach (mat_src ${MATERIAL_SRCS}) list(APPEND MATERIAL_BINS ${output_path}) endforeach() -if (IS_MOBILE_TARGET AND FILAMENT_SUPPORTS_OPENGL) - foreach (mat_src ${MATERIAL_ES2_SRCS}) - get_filename_component(localname "${mat_src}" NAME_WE) - get_filename_component(fullname "${mat_src}" ABSOLUTE) - set(output_path "${MATERIAL_DIR}/${localname}.filamat") - - add_custom_command( - OUTPUT ${output_path} - COMMAND matc -a opengl -p ${MATC_TARGET} ${MATC_OPT_FLAGS} -o ${output_path} ${fullname} - MAIN_DEPENDENCY ${fullname} - DEPENDS matc - COMMENT "Compiling material ${mat_src} to ${output_path}" - ) - list(APPEND MATERIAL_BINS ${output_path}) - endforeach () -endif () - # Additional dependencies on included files for materials add_custom_command( diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 227759769d..1dd11cd455 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -154,6 +154,19 @@ enum class ShaderLanguage { MSL = 3, }; +static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) { + switch (shaderLanguage) { + case ShaderLanguage::ESSL1: + return "ESSL 1.0"; + case ShaderLanguage::ESSL3: + return "ESSL 3.0"; + case ShaderLanguage::SPIRV: + return "SPIR-V"; + case ShaderLanguage::MSL: + return "MSL"; + } +} + /** * Bitmask for selecting render buffers */ diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 80ef41856b..ed48c52846 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -172,6 +172,7 @@ public: using Platform = backend::Platform; using Backend = backend::Backend; using DriverConfig = backend::Platform::DriverConfig; + using FeatureLevel = backend::FeatureLevel; /** * Config is used to define the memory footprint used by the engine, such as the @@ -351,6 +352,12 @@ public: */ Builder& sharedContext(void* sharedContext) noexcept; + /** + * @param featureLevel The feature level at which initialize Filament. + * @return A reference to this Builder for chaining calls. + */ + Builder& featureLevel(FeatureLevel featureLevel) noexcept; + #if UTILS_HAS_THREADING /** * Creates the filament Engine asynchronously. @@ -482,9 +489,6 @@ public: */ static void destroy(Engine* engine); - using FeatureLevel = backend::FeatureLevel; - - /** * Query the feature level supported by the selected backend. * diff --git a/filament/src/Froxelizer.cpp b/filament/src/Froxelizer.cpp index 52e0d71a84..c469932c25 100644 --- a/filament/src/Froxelizer.cpp +++ b/filament/src/Froxelizer.cpp @@ -104,12 +104,12 @@ Froxelizer::Froxelizer(FEngine& engine) static_assert(std::is_same_v, "Record Buffer must use bytes"); - if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) { + DriverApi& driverApi = engine.getDriverApi(); + + if (UTILS_UNLIKELY(driverApi.getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) { return; } - DriverApi& driverApi = engine.getDriverApi(); - mFroxelBufferEntryCount = std::min( FROXEL_BUFFER_MAX_ENTRY_COUNT, engine.getDriverApi().getMaxUniformBufferSize() / 16u); diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 4f176c1014..27173309ff 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -380,7 +380,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph // generate depth pass at the requested resolution auto& structurePass = fg.addPass("Structure Pass", [&](FrameGraph::Builder& builder, auto& data) { - bool const isES2 = mEngine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0; + bool const isES2 = mEngine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0; data.depth = builder.createTexture("Structure Buffer", { .width = width, .height = height, .levels = uint8_t(levelCount), diff --git a/filament/src/RendererUtils.cpp b/filament/src/RendererUtils.cpp index e45ce8c7d9..62e7a299ac 100644 --- a/filament/src/RendererUtils.cpp +++ b/filament/src/RendererUtils.cpp @@ -100,7 +100,7 @@ FrameGraphId RendererUtils::colorPass( "Depth/Stencil Buffer" : "Depth Buffer"; bool const isES2 = - engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0; + engine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0; TextureFormat const stencilFormat = isES2 ? TextureFormat::DEPTH24_STENCIL8 : TextureFormat::DEPTH32F_STENCIL8; diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 84bb55f4a0..642581f005 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -67,6 +67,7 @@ struct Engine::BuilderDetails { Backend mBackend = Backend::DEFAULT; Platform* mPlatform = nullptr; Engine::Config mConfig; + FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1; void* mSharedContext = nullptr; static Config validateConfig(const Config* pConfig) noexcept; }; @@ -185,6 +186,7 @@ static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 }; FEngine::FEngine(Engine::Builder const& builder) : mBackend(builder->mBackend), + mActiveFeatureLevel(builder->mFeatureLevel), mPlatform(builder->mPlatform), mSharedGLContext(builder->mSharedContext), mPostProcessManager(*this), @@ -326,15 +328,12 @@ void FEngine::init() { driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1, { zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); -#ifdef FILAMENT_TARGET_MOBILE if (UTILS_UNLIKELY(mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)) { FMaterial::DefaultMaterialBuilder defaultMaterialBuilder; defaultMaterialBuilder.package( MATERIALS_DEFAULTMATERIAL0_DATA, MATERIALS_DEFAULTMATERIAL0_SIZE); mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast(this))); - } else -#endif - { + } else { mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this)); FMaterial::DefaultMaterialBuilder defaultMaterialBuilder; @@ -1204,6 +1203,11 @@ Engine::Builder& Engine::Builder::config(Engine::Config const* config) noexcept return *this; } +Engine::Builder& Engine::Builder::featureLevel(FeatureLevel featureLevel) noexcept { + mImpl->mFeatureLevel = featureLevel; + return *this; +} + Engine::Builder& Engine::Builder::sharedContext(void* sharedContext) noexcept { mImpl->mSharedContext = sharedContext; return *this; diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index e7d910002d..e7c9e8d95f 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -231,7 +231,7 @@ public: default: return backend::ShaderLanguage::ESSL3; case Backend::OPENGL: - return mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0 + return getDriver().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0 ? backend::ShaderLanguage::ESSL1 : backend::ShaderLanguage::ESSL3; case Backend::VULKAN: return backend::ShaderLanguage::SPIRV; diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index bd89267af6..03cd2f8605 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -57,7 +57,9 @@ static MaterialParser* createParser(Backend backend, ShaderLanguage language, } ASSERT_PRECONDITION(materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND, - "the material was not built for the %s backend\n", backendToString(backend)); + "the material was not built for the %s backend and %s shader language\n", + backendToString(backend), + shaderLanguageToString(language)); ASSERT_PRECONDITION(materialResult == MaterialParser::ParseResult::SUCCESS, "could not parse the material package"); @@ -184,7 +186,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) success = parser->getUIB(&mUniformInterfaceBlock); assert_invariant(success); - if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) { + if (UTILS_UNLIKELY(engine.getShaderLanguage() == ShaderLanguage::ESSL1)) { success = parser->getBindingUniformInfo(&mBindingUniformInfo); assert_invariant(success); @@ -258,7 +260,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) mSpecializationConstants.push_back({ +ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS, (bool)powerVrShaderWorkarounds }); - if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) { + if (UTILS_UNLIKELY(engine.getShaderLanguage() == ShaderLanguage::ESSL1)) { // The actual value of this spec-constant is set in the OpenGLDriver backend. mSpecializationConstants.push_back({ +ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION, @@ -640,7 +642,6 @@ Program FMaterial::getProgramWithVariants( FEngine const& engine = mEngine; const ShaderModel sm = engine.getShaderModel(); const bool isNoop = engine.getBackend() == Backend::NOOP; - const FeatureLevel engineFeatureLevel = engine.getActiveFeatureLevel(); /* * Vertex shader */ @@ -694,7 +695,7 @@ Program FMaterial::getProgramWithVariants( } } - if (engineFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + if (UTILS_UNLIKELY(mEngine.getShaderLanguage() == ShaderLanguage::ESSL1)) { assert_invariant(!mBindingUniformInfo.empty()); for (auto const& [index, uniforms] : mBindingUniformInfo) { program.uniforms(uint32_t(index), uniforms); diff --git a/filament/src/details/Skybox.cpp b/filament/src/details/Skybox.cpp index 969eccdb45..7c0dac1512 100644 --- a/filament/src/details/Skybox.cpp +++ b/filament/src/details/Skybox.cpp @@ -118,12 +118,9 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept FMaterial const* FSkybox::createMaterial(FEngine& engine) { Material::Builder builder; -#ifdef FILAMENT_TARGET_MOBILE if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == Engine::FeatureLevel::FEATURE_LEVEL_0)) { builder.package(MATERIALS_SKYBOX0_DATA, MATERIALS_SKYBOX0_SIZE); - } else -#endif - { + } else { builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE); } auto material = builder.build(engine); diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index b02d50c5c7..6308e1ef17 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -662,7 +662,6 @@ void FView::bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noe mPerViewUniforms.bind(driver); if (UTILS_UNLIKELY(driver.getFeatureLevel() == backend::FeatureLevel::FEATURE_LEVEL_0)) { - // FIXME: should be okay to use driver (instead of engine) for FEATURE_LEVEL_0 checks return; } diff --git a/libs/filamentapp/materials/transparentColor.mat b/libs/filamentapp/materials/transparentColor.mat index c43f9410e7..7ad51944dd 100644 --- a/libs/filamentapp/materials/transparentColor.mat +++ b/libs/filamentapp/materials/transparentColor.mat @@ -9,7 +9,8 @@ material { blending : transparent, culling : none, depthCulling : false, - shadingModel : unlit + shadingModel : unlit, + featureLevel : 0 } fragment { diff --git a/libs/filamentapp/src/FilamentApp.cpp b/libs/filamentapp/src/FilamentApp.cpp index 51ba611d14..7970c61f3a 100644 --- a/libs/filamentapp/src/FilamentApp.cpp +++ b/libs/filamentapp/src/FilamentApp.cpp @@ -603,10 +603,14 @@ FilamentApp::Window::Window(FilamentApp* filamentApp, return Engine::Builder() .backend(backend) .platform(mFilamentApp->mVulkanPlatform) + .featureLevel(config.featureLevel) .build(); #endif } - return Engine::Builder().backend(backend).build(); + return Engine::Builder() + .backend(backend) + .featureLevel(config.featureLevel) + .build(); }; if (config.headless) { @@ -647,10 +651,8 @@ FilamentApp::Window::Window(FilamentApp* filamentApp, #endif - // Select the feature level to use - config.featureLevel = std::min(config.featureLevel, - mFilamentApp->mEngine->getSupportedFeatureLevel()); - mFilamentApp->mEngine->setActiveFeatureLevel(config.featureLevel); + // Write back the active feature level. + config.featureLevel = mFilamentApp->mEngine->getActiveFeatureLevel(); mSwapChain = mFilamentApp->mEngine->createSwapChain( nativeSwapChain, filament::SwapChain::CONFIG_HAS_STENCIL_BUFFER); diff --git a/samples/hellotriangle.cpp b/samples/hellotriangle.cpp index c6469fc1b3..4477429dd6 100644 --- a/samples/hellotriangle.cpp +++ b/samples/hellotriangle.cpp @@ -122,6 +122,7 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) { int main(int argc, char** argv) { App app{}; app.config.title = "hellotriangle"; + app.config.featureLevel = backend::FeatureLevel::FEATURE_LEVEL_0; handleCommandLineArguments(argc, argv, &app); auto setup = [&app](Engine* engine, View* view, Scene* scene) { diff --git a/samples/materials/bakedColor.mat b/samples/materials/bakedColor.mat index ee10a3035e..c78cef16ac 100644 --- a/samples/materials/bakedColor.mat +++ b/samples/materials/bakedColor.mat @@ -4,7 +4,8 @@ material { color ], shadingModel : unlit, - culling : none + culling : none, + featureLevel : 0 } fragment {