From b4d842c3428bb60f31eb2d1cca82fd6f2e8330ea Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 3 Apr 2023 13:04:06 -0700 Subject: [PATCH] ES2 support: filament and filamat changes This CL contains two parts: - changes to matc/filamat - changes to filament itself Filamat can now generate ES2 compatible shaders. Only the unlit variant is supported. Fog and picking are supported as well. post-processing, skinning, instancing, all lighting and shadowing are not supported. Filament is updated to not issue commands that are not supported in ES2. Addtionnally, the hello-triangle sample is updated to work on an ES2 device. --- .../src/main/AndroidManifest.xml | 2 + .../filament/hellotriangle/MainActivity.kt | 25 +++- .../src/main/materials/baked_color.mat | 2 +- .../src/main/materials/baked_color_es2.mat | 33 +++++ filament/CMakeLists.txt | 22 +++ filament/src/Froxelizer.cpp | 12 +- filament/src/MaterialParser.cpp | 80 +++++++++++ filament/src/MaterialParser.h | 21 +++ filament/src/RendererUtils.cpp | 8 +- filament/src/details/Engine.cpp | 85 ++++++----- filament/src/details/Material.cpp | 100 +++++++++---- filament/src/details/Material.h | 9 ++ filament/src/details/MorphTargetBuffer.cpp | 17 ++- filament/src/details/Skybox.cpp | 14 +- filament/src/details/View.cpp | 5 + filament/src/materials/defaultMaterial0.mat | 12 ++ filament/src/materials/skybox0.mat | 60 ++++++++ .../include/filament/MaterialChunkType.h | 2 + .../private/filament/BufferInterfaceBlock.h | 2 + libs/filabridge/src/BufferInterfaceBlock.cpp | 6 +- libs/filamat/src/GLSLPostProcessor.cpp | 6 + libs/filamat/src/MaterialBuilder.cpp | 122 +++++++++++++++- .../src/eiff/MaterialInterfaceBlockChunk.cpp | 40 +++++- .../src/eiff/MaterialInterfaceBlockChunk.h | 38 ++++- libs/filamat/src/sca/GLSLTools.cpp | 7 +- libs/filamat/src/shaders/CodeGenerator.cpp | 135 +++++++++++++----- libs/filamat/src/shaders/CodeGenerator.h | 29 ++-- libs/filamat/src/shaders/ShaderGenerator.cpp | 17 ++- libs/filamat/src/shaders/UibGenerator.cpp | 84 +++++------ shaders/src/common_instancing.glsl | 15 +- shaders/src/getters.vs | 2 + shaders/src/main.fs | 8 ++ shaders/src/main.vs | 6 +- shaders/src/varyings.glsl | 2 + tools/matc/src/matc/CommandlineConfig.cpp | 1 + tools/matc/src/matc/ParametersProcessor.cpp | 4 +- 36 files changed, 845 insertions(+), 188 deletions(-) create mode 100644 android/samples/sample-hello-triangle/src/main/materials/baked_color_es2.mat create mode 100644 filament/src/materials/defaultMaterial0.mat create mode 100644 filament/src/materials/skybox0.mat diff --git a/android/samples/sample-hello-triangle/src/main/AndroidManifest.xml b/android/samples/sample-hello-triangle/src/main/AndroidManifest.xml index 9b149c2580..7ebe637288 100644 --- a/android/samples/sample-hello-triangle/src/main/AndroidManifest.xml +++ b/android/samples/sample-hello-triangle/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + , @@ -132,8 +136,12 @@ void Froxelizer::terminate(DriverApi& driverApi) noexcept { mPlanesX = nullptr; mDistancesZ = nullptr; - driverApi.destroyBufferObject(mRecordsBuffer); - driverApi.destroyTexture(mFroxelTexture); + if (mRecordsBuffer) { + driverApi.destroyBufferObject(mRecordsBuffer); + } + if (mFroxelTexture) { + driverApi.destroyTexture(mFroxelTexture); + } } void Froxelizer::setOptions(float zLightNear, float zLightFar) noexcept { diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index ae87663068..8d8f383b64 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -168,6 +168,20 @@ bool MaterialParser::getUniformBlockBindings( return ChunkUniformBlockBindings::unflatten(unflattener, value); } +bool MaterialParser::getBindingUniformInfo(BindingUniformInfoContainer* container) const noexcept { + auto [start, end] = mImpl.mChunkContainer.getChunkRange(MaterialBindingUniformInfo); + if (start == end) return false; + Unflattener unflattener(start, end); + return ChunkBindingUniformInfo::unflatten(unflattener, container); +} + +bool MaterialParser::getAttributeInfo(AttributeInfoContainer* container) const noexcept { + auto [start, end] = mImpl.mChunkContainer.getChunkRange(MaterialAttributeInfo); + if (start == end) return false; + Unflattener unflattener(start, end); + return ChunkAttributeInfo::unflatten(unflattener, container); +} + bool MaterialParser::getSamplerBlockBindings( SamplerGroupBindingInfoList* pSamplerGroupInfoList, SamplerBindingToNameMap* pSamplerBindingToNameMap) const noexcept { @@ -507,6 +521,72 @@ bool ChunkUniformBlockBindings::unflatten(filaflat::Unflattener& unflattener, return true; } +bool ChunkBindingUniformInfo::unflatten(filaflat::Unflattener& unflattener, + MaterialParser::BindingUniformInfoContainer* bindingUniformInfo) { + uint8_t bindingPointCount; + if (!unflattener.read(&bindingPointCount)) { + return false; + } + bindingUniformInfo->reserve(bindingPointCount); + for (size_t i = 0; i < bindingPointCount; i++) { + uint8_t index; + if (!unflattener.read(&index)) { + return false; + } + uint8_t uniformCount; + if (!unflattener.read(&uniformCount)) { + return false; + } + + Program::UniformInfo uniforms = Program::UniformInfo::with_capacity(uniformCount); + for (size_t j = 0; j < uniformCount; j++) { + utils::CString name; + if (!unflattener.read(&name)) { + return false; + } + uint16_t offset; + if (!unflattener.read(&offset)) { + return false; + } + uint8_t size; + if (!unflattener.read(&size)) { + return false; + } + uint8_t type; + if (!unflattener.read(&type)) { + return false; + } + uniforms.push_back({ name, offset, size, UniformType(type) }); + } + bindingUniformInfo->emplace_back(UniformBindingPoints(index), std::move(uniforms)); + } + return true; +} + +bool ChunkAttributeInfo::unflatten(filaflat::Unflattener& unflattener, + MaterialParser::AttributeInfoContainer* attributeInfoContainer) { + + uint8_t attributeCount; + if (!unflattener.read(&attributeCount)) { + return false; + } + + attributeInfoContainer->reserve(attributeCount); + + for (size_t j = 0; j < attributeCount; j++) { + utils::CString name; + if (!unflattener.read(&name)) { + return false; + } + uint8_t location; + if (!unflattener.read(&location)) { + return false; + } + attributeInfoContainer->emplace_back(name, location); + } + + return true; +} bool ChunkSamplerBlockBindings::unflatten(Unflattener& unflattener, SamplerGroupBindingInfoList* pSamplerGroupBindingInfoList, diff --git a/filament/src/MaterialParser.h b/filament/src/MaterialParser.h index 154cb743f6..9dd6440896 100644 --- a/filament/src/MaterialParser.h +++ b/filament/src/MaterialParser.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -74,6 +75,16 @@ public: SamplerBindingToNameMap* pSamplerBindingToNameMap) const noexcept; bool getConstants(utils::FixedCapacityVector* value) const noexcept; + using BindingUniformInfoContainer = utils::FixedCapacityVector< + std::pair>; + + bool getBindingUniformInfo(BindingUniformInfoContainer* container) const noexcept; + + using AttributeInfoContainer = utils::FixedCapacityVector< + std::pair>; + + bool getAttributeInfo(AttributeInfoContainer* container) const noexcept; + bool getDepthWriteSet(bool* value) const noexcept; bool getDepthWrite(bool* value) const noexcept; bool getDoubleSidedSet(bool* value) const noexcept; @@ -166,6 +177,16 @@ struct ChunkUniformBlockBindings { utils::FixedCapacityVector>* uniformBlockBindings); }; +struct ChunkBindingUniformInfo { + static bool unflatten(filaflat::Unflattener& unflattener, + MaterialParser::BindingUniformInfoContainer* bindingUniformInfo); +}; + +struct ChunkAttributeInfo { + static bool unflatten(filaflat::Unflattener& unflattener, + MaterialParser::AttributeInfoContainer* attributeInfoContainer); +}; + struct ChunkSamplerBlockBindings { static bool unflatten(filaflat::Unflattener& unflattener, SamplerGroupBindingInfoList* pSamplerGroupBindingInfoList, diff --git a/filament/src/RendererUtils.cpp b/filament/src/RendererUtils.cpp index 5d514f1a16..e62312d229 100644 --- a/filament/src/RendererUtils.cpp +++ b/filament/src/RendererUtils.cpp @@ -98,8 +98,14 @@ FrameGraphId RendererUtils::colorPass( TargetBufferFlags::STENCIL : TargetBufferFlags::NONE; const char* const name = config.enabledStencilBuffer ? "Depth/Stencil Buffer" : "Depth Buffer"; - TextureFormat const format = config.enabledStencilBuffer ? + TextureFormat format = config.enabledStencilBuffer ? TextureFormat::DEPTH32F_STENCIL8 : TextureFormat::DEPTH32F; + + if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) { + // FIXME: handle stencil buffer + format = TextureFormat::DEPTH24; + } + data.depth = builder.createTexture(name, { .width = colorBufferDesc.width, .height = colorBufferDesc.height, diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index c093b02304..4f2fa0eb28 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -314,74 +314,81 @@ void FEngine::init() { }); } + // initialize the dummy textures so that their contents are not undefined + static const uint32_t zeroes[6] = {0}; + static const uint32_t ones = 0xffffffff; + mDefaultIblTexture = downcast(Texture::Builder() .width(1).height(1).levels(1) .format(Texture::InternalFormat::RGBA8) .sampler(Texture::Sampler::SAMPLER_CUBEMAP) .build(*this)); + driverApi.update3DImage(mDefaultIblTexture->getHwHandle(), 0, 0, 0, 0, 1, 1, 6, + { zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE }); + // 3 bands = 9 float3 const float sh[9 * 3] = { 0.0f }; mDefaultIbl = downcast(IndirectLight::Builder() .irradiance(3, reinterpret_cast(sh)) .build(*this)); - mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this)); + mDefaultRenderTarget = driverApi.createDefaultRenderTarget(); - // Always initialize the default material, most materials' depth shaders fallback on it. - mDefaultMaterial = downcast( - FMaterial::DefaultMaterialBuilder() - .package(MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE) - .build(*const_cast(this))); - - // Create a dummy morph target buffer. - mDummyMorphTargetBuffer = createMorphTargetBuffer(FMorphTargetBuffer::EmptyMorphTargetBuilder()); - - float3 dummyPositions[1] = {}; - short4 dummyTangents[1] = {}; - mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0); - mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0); + // Create a dummy morph target buffer, without using the builder + mDummyMorphTargetBuffer = createMorphTargetBuffer( + FMorphTargetBuffer::EmptyMorphTargetBuilder()); // create dummy textures we need throughout the engine - mDummyOneTexture = driverApi.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); - mDummyOneTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, - TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); - - mDummyZeroTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, - TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); - mDummyZeroTexture = driverApi.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); - - // initialize the dummy textures so that their contents are not undefined - - static const uint32_t zeroes[6] = {0}; - static const uint32_t ones = 0xffffffff; - - driverApi.update3DImage(mDefaultIblTexture->getHwHandle(), 0, 0, 0, 0, 1, 1, 6, - { zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE }); - driverApi.update3DImage(mDummyOneTexture, 0, 0, 0, 0, 1, 1, 1, { &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); - driverApi.update3DImage(mDummyOneTextureArray, 0, 0, 0, 0, 1, 1, 1, - { &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); - driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1, { zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); - driverApi.update3DImage(mDummyZeroTextureArray, 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 + { + mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this)); - mDefaultRenderTarget = driverApi.createDefaultRenderTarget(); + FMaterial::DefaultMaterialBuilder defaultMaterialBuilder; + defaultMaterialBuilder.package( + MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE); + mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast(this))); - mPostProcessManager.init(); - mLightManager.init(*this); - mDFG.init(*this); + float3 dummyPositions[1] = {}; + short4 dummyTangents[1] = {}; + mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0); + mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0); + + mDummyOneTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, + TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); + + mDummyZeroTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, + TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT); + + driverApi.update3DImage(mDummyOneTextureArray, 0, 0, 0, 0, 1, 1, 1, + { &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); + + driverApi.update3DImage(mDummyZeroTextureArray, 0, 0, 0, 0, 1, 1, 1, + { zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE }); + + mPostProcessManager.init(); + mLightManager.init(*this); + mDFG.init(*this); + } } FEngine::~FEngine() noexcept { diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index f6ef4c68e1..d1cb94fa3b 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -152,18 +152,28 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) UTILS_UNUSED_IN_RELEASE bool const nameOk = parser->getName(&mName); assert_invariant(nameOk); - uint8_t featureLevel = 1; - parser->getFeatureLevel(&featureLevel); - assert_invariant(featureLevel <= 3); - mFeatureLevel = [featureLevel]() -> FeatureLevel { - switch (featureLevel) { - default: - case 1: return FeatureLevel::FEATURE_LEVEL_1; - case 2: return FeatureLevel::FEATURE_LEVEL_2; - case 3: return FeatureLevel::FEATURE_LEVEL_3; + mFeatureLevel = [parser]() -> FeatureLevel { + // code written this way so the IDE will complain when/if we add a FeatureLevel + uint8_t level = 1; + parser->getFeatureLevel(&level); + assert_invariant(level <= 3); + FeatureLevel featureLevel = FeatureLevel::FEATURE_LEVEL_1; + switch (FeatureLevel(level)) { + case FeatureLevel::FEATURE_LEVEL_0: + case FeatureLevel::FEATURE_LEVEL_1: + case FeatureLevel::FEATURE_LEVEL_2: + case FeatureLevel::FEATURE_LEVEL_3: + featureLevel = FeatureLevel(level); + break; } + return featureLevel; }(); + // TODO: this should probably be checked in build() + // if the engine is at feature level 0, so must the material be. + assert_invariant((engine.getActiveFeatureLevel() != FeatureLevel::FEATURE_LEVEL_0) || + (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)); + UTILS_UNUSED_IN_RELEASE bool success; success = parser->getSIB(&mSamplerInterfaceBlock); @@ -172,9 +182,27 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) success = parser->getUIB(&mUniformInterfaceBlock); assert_invariant(success); - // read the uniform binding list - success = parser->getUniformBlockBindings(&mUniformBlockBindings); - assert_invariant(success || mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_2); + // TODO: currently, the feature level used is determined by the material because we + // don't have "feature level" variants. In the future, we could instead pick + // the code path based on the engine's feature level. + + if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + // these chunks are only needed for materials at feature level 0 + // TODO: remove this assert when we support feature level variants + assert_invariant(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0); + + success = parser->getBindingUniformInfo(&mBindingUniformInfo); + assert_invariant(success); + + success = parser->getAttributeInfo(&mAttributeInfo); + assert_invariant(success); + } + + if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_1) { + // this chunk is not needed for materials at feature level 2 and above + success = parser->getUniformBlockBindings(&mUniformBlockBindings); + assert_invariant(success); + } success = parser->getSamplerBlockBindings( &mSamplerGroupBindingInfoList, &mSamplerBindingToNameMap); @@ -201,19 +229,27 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) // Verify that all the constant specializations exist in the material and that their types match. // The first specialization constants are defined internally by Filament. // The subsequent constants are user-defined in the material. - mSpecializationConstants.reserve(constants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS); - mSpecializationConstants.push_back({0, (int)mEngine.getSupportedFeatureLevel()}); - mSpecializationConstants.push_back({1, (int)CONFIG_MAX_INSTANCES}); + + // Feature level 0 doesn't support instancing + int const maxInstanceCount = (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) + ? 1 : CONFIG_MAX_INSTANCES; + const bool staticTextureWorkaround = - mEngine.getDriverApi().isWorkaroundNeeded(Workaround::A8X_STATIC_TEXTURE_TARGET_ERROR); + engine.getDriverApi().isWorkaroundNeeded(Workaround::A8X_STATIC_TEXTURE_TARGET_ERROR); + + mSpecializationConstants.reserve(constants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS); + mSpecializationConstants.push_back({0, (int)engine.getSupportedFeatureLevel()}); + mSpecializationConstants.push_back({1, (int)maxInstanceCount}); mSpecializationConstants.push_back({2, (bool)staticTextureWorkaround}); + for (const auto& [name, value] : builder->mConstantSpecializations) { auto found = std::find_if( constants.begin(), constants.end(), [name = name](const auto& constant) { return strncmp(constant.name.data(), name.data(), name.length()) == 0; }); ASSERT_PRECONDITION(found != constants.end(), - "The material %s does not have a constant parameter named %s.", mName.c_str_safe(), name.c_str()); + "The material %s does not have a constant parameter named %s.", + mName.c_str_safe(), name.c_str()); const char* const types[3] = {"an int", "a float", "a bool"}; const char* const errorMessage = "The constant parameter %s on material %s is of type %s, but %s was " @@ -232,8 +268,9 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder) name.c_str(), mName.c_str_safe(), "bool", types[value.index()]); break; } - uint32_t index = std::distance(constants.begin(), found) + CONFIG_MAX_RESERVED_SPEC_CONSTANTS; - mSpecializationConstants.push_back({index, value}); + uint32_t const index = + std::distance(constants.begin(), found) + CONFIG_MAX_RESERVED_SPEC_CONSTANTS; + mSpecializationConstants.push_back({ index, value }); } parser->getShading(&mShading); @@ -463,14 +500,15 @@ Program FMaterial::getProgramWithVariants( Variant variant, Variant vertexVariant, Variant fragmentVariant) const noexcept { - const ShaderModel sm = mEngine.getShaderModel(); - const bool isNoop = mEngine.getBackend() == Backend::NOOP; - + FEngine const& engine = mEngine; + const ShaderModel sm = engine.getShaderModel(); + const bool isNoop = engine.getBackend() == Backend::NOOP; + const FeatureLevel engineFeatureLevel = engine.getActiveFeatureLevel(); /* * Vertex shader */ - ShaderContent& vsBuilder = mEngine.getVertexShaderContent(); + ShaderContent& vsBuilder = engine.getVertexShaderContent(); UTILS_UNUSED_IN_RELEASE bool const vsOK = mMaterialParser->getShader(vsBuilder, sm, vertexVariant, ShaderStage::VERTEX); @@ -484,11 +522,17 @@ Program FMaterial::getProgramWithVariants( * Fragment shader */ - ShaderContent& fsBuilder = mEngine.getFragmentShaderContent(); + ShaderContent& fsBuilder = engine.getFragmentShaderContent(); UTILS_UNUSED_IN_RELEASE bool const fsOK = mMaterialParser->getShader(fsBuilder, sm, fragmentVariant, ShaderStage::FRAGMENT); + ASSERT_POSTCONDITION( + (engineFeatureLevel != FeatureLevel::FEATURE_LEVEL_0) || + (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0), + "Engine is running a FEATURE_LEVEL_0 but material '%s' is not.", + mName.c_str()); + ASSERT_POSTCONDITION(isNoop || (fsOK && !fsBuilder.empty()), "The material '%s' has not been compiled to include the required " "GLSL or SPIR-V chunks for the fragment shader (variant=0x%x, filtered=0x%x).", @@ -519,6 +563,14 @@ Program FMaterial::getProgramWithVariants( } } + if (engineFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + assert_invariant(!mBindingUniformInfo.empty()); + for (auto const& [index, uniforms] : mBindingUniformInfo) { + program.uniforms(uint32_t(index), uniforms); + } + program.attributes(mAttributeInfo); + } + program.specializationConstants(mSpecializationConstants); return program; diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index a9bc190bbb..46409b6fd2 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -231,6 +231,15 @@ private: utils::FixedCapacityVector> mUniformBlockBindings; utils::FixedCapacityVector mDepthVariants; // only populated with default material + using BindingUniformInfoContainer = utils::FixedCapacityVector< + std::pair>; + + BindingUniformInfoContainer mBindingUniformInfo; + + using AttributeInfoContainer = utils::FixedCapacityVector>; + + AttributeInfoContainer mAttributeInfo; + SamplerGroupBindingInfoList mSamplerGroupBindingInfoList; SamplerBindingToNameMap mSamplerBindingToNameMap; utils::FixedCapacityVector mSpecializationConstants; diff --git a/filament/src/details/MorphTargetBuffer.cpp b/filament/src/details/MorphTargetBuffer.cpp index f7c1221495..6102b3c116 100644 --- a/filament/src/details/MorphTargetBuffer.cpp +++ b/filament/src/details/MorphTargetBuffer.cpp @@ -102,6 +102,11 @@ FMorphTargetBuffer::EmptyMorphTargetBuilder::EmptyMorphTargetBuilder() { FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder) : mVertexCount(builder->mVertexCount), mCount(builder->mCount) { + + if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) { + return; + } + FEngine::DriverApi& driver = engine.getDriverApi(); // create buffer (here a texture) to store the morphing vertex data @@ -129,9 +134,15 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder) void FMorphTargetBuffer::terminate(FEngine& engine) { FEngine::DriverApi& driver = engine.getDriverApi(); - driver.destroySamplerGroup(mSbHandle); - driver.destroyTexture(mTbHandle); - driver.destroyTexture(mPbHandle); + if (UTILS_LIKELY(mSbHandle)) { + driver.destroySamplerGroup(mSbHandle); + } + if (UTILS_LIKELY(mTbHandle)) { + driver.destroyTexture(mTbHandle); + } + if (UTILS_LIKELY(mPbHandle)) { + driver.destroyTexture(mPbHandle); + } } void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex, diff --git a/filament/src/details/Skybox.cpp b/filament/src/details/Skybox.cpp index d3e606d418..969eccdb45 100644 --- a/filament/src/details/Skybox.cpp +++ b/filament/src/details/Skybox.cpp @@ -117,9 +117,17 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept } FMaterial const* FSkybox::createMaterial(FEngine& engine) { - FMaterial const* material = downcast(Material::Builder().package( - MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE).build(engine)); - return material; + 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 + { + builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE); + } + auto material = builder.build(engine); + return downcast(material); } void FSkybox::terminate(FEngine& engine) noexcept { diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index b5a40115ec..ced953cd2d 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -651,6 +651,11 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena, void FView::bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept { 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; + } + driver.bindUniformBuffer(+UniformBindingPoints::LIGHTS, mLightUbh); diff --git a/filament/src/materials/defaultMaterial0.mat b/filament/src/materials/defaultMaterial0.mat new file mode 100644 index 0000000000..914d29c3d1 --- /dev/null +++ b/filament/src/materials/defaultMaterial0.mat @@ -0,0 +1,12 @@ +material { + name : "Filament Default Material", + shadingModel : unlit, + featureLevel: 0 +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + material.baseColor.rgb = vec3(0.8); + } +} diff --git a/filament/src/materials/skybox0.mat b/filament/src/materials/skybox0.mat new file mode 100644 index 0000000000..2891e32f4b --- /dev/null +++ b/filament/src/materials/skybox0.mat @@ -0,0 +1,60 @@ +material { + name : Skybox, + parameters : [ + { + type : int, + name : showSun + }, + { + type : int, + name : constantColor + }, + { + type : samplerCubemap, + name : skybox + }, + { + type : float4, + name : color + } + ], + variables : [ + eyeDirection + ], + vertexDomain : device, + depthWrite : false, + shadingModel : unlit, + variantFilter : [ skinning, shadowReceiver, vsm ], + culling: none, + featureLevel: 0 +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + vec4 sky; + if (materialParams.constantColor != 0) { + sky = materialParams.color; + } else { + sky = vec4(textureCube(materialParams_skybox, variable_eyeDirection.xyz).rgb, 1.0); + sky.rgb *= frameUniforms.iblLuminance; + } + if (materialParams.showSun != 0 && frameUniforms.sun.w >= 0.0) { + vec3 direction = normalize(variable_eyeDirection.xyz); + // Assume the sun is a sphere + vec3 sun = frameUniforms.lightColorIntensity.rgb * + (frameUniforms.lightColorIntensity.a * (4.0 * PI)); + float cosAngle = dot(direction, frameUniforms.lightDirection); + float x = (cosAngle - frameUniforms.sun.x) * frameUniforms.sun.z; + float gradient = pow(1.0 - saturate(x), frameUniforms.sun.w); + sky.rgb = sky.rgb + gradient * sun; + } + material.baseColor = sky; + } +} + +vertex { + void materialVertex(inout MaterialVertexInputs material) { + material.eyeDirection.xyz = material.worldPosition.xyz; + } +} diff --git a/libs/filabridge/include/filament/MaterialChunkType.h b/libs/filabridge/include/filament/MaterialChunkType.h index 5d3e95ee3b..a995c5672e 100644 --- a/libs/filabridge/include/filament/MaterialChunkType.h +++ b/libs/filabridge/include/filament/MaterialChunkType.h @@ -47,6 +47,8 @@ enum UTILS_PUBLIC ChunkType : uint64_t { MaterialShaderModels = charTo64bitNum("MAT_SMDL"), MaterialSamplerBindings = charTo64bitNum("MAT_SAMP"), MaterialUniformBindings = charTo64bitNum("MAT_UNIF"), + MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"), + MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"), MaterialProperties = charTo64bitNum("MAT_PROP"), MaterialConstants = charTo64bitNum("MAT_CONS"), diff --git a/libs/filabridge/include/private/filament/BufferInterfaceBlock.h b/libs/filabridge/include/private/filament/BufferInterfaceBlock.h index a8240f7016..2d7c8963de 100644 --- a/libs/filabridge/include/private/filament/BufferInterfaceBlock.h +++ b/libs/filabridge/include/private/filament/BufferInterfaceBlock.h @@ -41,6 +41,7 @@ public: uint32_t size; backend::UniformType type; backend::Precision precision{}; + backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1; std::string_view structName{}; uint32_t stride{}; std::string_view sizeName{}; @@ -67,6 +68,7 @@ public: bool isArray; // true if the field is an array uint32_t size; // size of the array in elements, or 0 if not an array Precision precision; // precision of this field + backend::FeatureLevel minFeatureLevel; // below this feature level, this field is not needed utils::CString structName; // name of this field structure if type is STRUCT utils::CString sizeName; // name of the size parameter in the shader // returns offset in bytes of this field (at index if an array) diff --git a/libs/filabridge/src/BufferInterfaceBlock.cpp b/libs/filabridge/src/BufferInterfaceBlock.cpp index 1854d2b7da..96e725f95f 100644 --- a/libs/filabridge/src/BufferInterfaceBlock.cpp +++ b/libs/filabridge/src/BufferInterfaceBlock.cpp @@ -58,7 +58,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::add( for (auto const& item : list) { mEntries.push_back({ { item.name.data(), item.name.size() }, - 0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, + 0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.minFeatureLevel, { item.structName.data(), item.structName.size() }, { item.sizeName.data(), item.sizeName.size() } }); @@ -71,7 +71,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::addVariableSizedAr mHasVariableSizeArray = true; mEntries.push_back({ { item.name.data(), item.name.size() }, - 0, uint8_t(item.stride), item.type, true, 0, item.precision, + 0, uint8_t(item.stride), item.type, true, 0, item.precision, item.minFeatureLevel, { item.structName.data(), item.structName.size() }, { item.sizeName.data(), item.sizeName.size() } }); @@ -143,7 +143,7 @@ BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept FieldInfo& info = uniformsInfoList[i]; info = { e.name, offset, uint8_t(stride), e.type, e.isArray, e.size, - e.precision, e.structName, e.sizeName }; + e.precision, e.minFeatureLevel, e.structName, e.sizeName }; // record this uniform info infoMap[{ info.name.data(), info.name.size() }] = i; diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index e6acd8d7a7..0b39c13bd5 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -524,6 +524,12 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader, glslOptions.fragment.default_int_precision = glslOptions.es ? CompilerGLSL::Options::Precision::Mediump : CompilerGLSL::Options::Precision::Highp; + // TODO: this should be done only on the "feature level 0" variant + if (config.featureLevel == 0) { + // convert UBOs to plain uniforms if we're at feature level 0 + glslOptions.emit_uniform_buffer_as_plain_uniforms = true; + } + CompilerGLSL glslCompiler(std::move(spirv)); glslCompiler.set_common_options(glslOptions); diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index a5fcfc0fbd..44e17d3e33 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -21,6 +21,7 @@ #include "Includes.h" #include "MaterialVariants.h" #include "shaders/SibGenerator.h" +#include "shaders/UibGenerator.h" #ifndef FILAMAT_LITE # include "GLSLPostProcessor.h" @@ -47,6 +48,8 @@ #include #include +#include + #include #include #include @@ -531,7 +534,8 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept { param.samplerType, param.format, param.precision); } else if (param.isUniform()) { ibb.add({{{ param.name.data(), param.name.size() }, - uint32_t(param.size == 1u ? 0u : param.size), param.uniformType, param.precision }}); + uint32_t(param.size == 1u ? 0u : param.size), param.uniformType, + param.precision, FeatureLevel::FEATURE_LEVEL_0 }}); } } @@ -1085,6 +1089,17 @@ error: goto error; } + if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + if (mPlatform != Platform::MOBILE) { + slog.e << "Error: only platform `mobile` is supported at featureLevel 0." << io::endl; + goto error; + } + if (any(mTargetApi & ~TargetApi::OPENGL)) { + mTargetApi &= TargetApi::OPENGL; + slog.w << "Warning: only target `opengl` is supported at featureLevel 0." << io::endl; + } + } + // prepareToBuild must be called first, to populate mCodeGenPermutations. MaterialInfo info{}; prepareToBuild(info); @@ -1109,7 +1124,8 @@ error: CodeGenParams const semanticCodeGenParams = { .shaderModel = ShaderModel::MOBILE, .targetApi = TargetApi::OPENGL, - .targetLanguage = TargetLanguage::SPIRV + .targetLanguage = (info.featureLevel == FeatureLevel::FEATURE_LEVEL_0) ? + TargetLanguage::GLSL : TargetLanguage::SPIRV }; if (!findAllProperties(semanticCodeGenParams)) { @@ -1133,6 +1149,16 @@ error: // Generate all shaders and write the shader chunks. + if (mFeatureLevel == filament::backend::FeatureLevel::FEATURE_LEVEL_0) { + // at feature level 0, many variants are not supported + mVariantFilter |= uint32_t(UserVariantFilterBit::DIRECTIONAL_LIGHTING); + mVariantFilter |= uint32_t(UserVariantFilterBit::DYNAMIC_LIGHTING); + mVariantFilter |= uint32_t(UserVariantFilterBit::SHADOW_RECEIVER); + mVariantFilter |= uint32_t(UserVariantFilterBit::SKINNING); + mVariantFilter |= uint32_t(UserVariantFilterBit::VSM); + mVariantFilter |= uint32_t(UserVariantFilterBit::SSR); + } + std::vector variants; switch (mMaterialDomain) { case MaterialDomain::SURFACE: @@ -1186,6 +1212,15 @@ bool MaterialBuilder::checkMaterialLevelFeatures(MaterialInfo const& info) const const auto userSamplerCount = info.sib.getSize(); switch (info.featureLevel) { + case FeatureLevel::FEATURE_LEVEL_0: + // TODO: check FEATURE_LEVEL_0 features (e.g. unlit only, no texture arrays, etc...) + if (info.isLit) { + slog.e << "Error: material \"" << mMaterialName.c_str() + << "\" has feature level " << +info.featureLevel + << " and is not 'unlit'." << io::endl; + return false; + } + return true; case FeatureLevel::FEATURE_LEVEL_1: case FeatureLevel::FEATURE_LEVEL_2: { // TODO: we need constants somewhere for these values @@ -1272,6 +1307,33 @@ std::string MaterialBuilder::peek(backend::ShaderStage stage, } } +static Program::UniformInfo extractUniforms(BufferInterfaceBlock const& uib) noexcept { + auto list = uib.getFieldInfoList(); + Program::UniformInfo uniforms = Program::UniformInfo::with_capacity(list.size()); + + char const firstLetter = std::tolower( uib.getName().at(0) ); + std::string_view const nameAfterFirstLetter{ + uib.getName().data() + 1, uib.getName().size() - 1 }; + + for (auto const& item : list) { + // construct the fully qualified name + std::string qualified; + qualified.reserve(uib.getName().size() + item.name.size() + 1u); + qualified.append({ &firstLetter, 1u }); + qualified.append(nameAfterFirstLetter); + qualified.append("."); + qualified.append({ item.name.data(), item.name.size() }); + + uniforms.push_back({ + { qualified.data(), qualified.size() }, + item.offset, + uint8_t(item.size < 1u ? 1u : item.size), + item.type + }); + } + return uniforms; +} + void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo& info) const noexcept { container.emplace(ChunkType::MaterialVersion, MATERIAL_VERSION); container.emplace(ChunkType::MaterialFeatureLevel, (uint8_t)info.featureLevel); @@ -1281,6 +1343,62 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo& using namespace filament; + if (info.featureLevel == FeatureLevel::FEATURE_LEVEL_0) { + FixedCapacityVector> list({ + { UniformBindingPoints::PER_VIEW, + extractUniforms(UibGenerator::getPerViewUib()) }, + { UniformBindingPoints::PER_RENDERABLE, + extractUniforms(UibGenerator::getPerRenderableUib()) }, + { UniformBindingPoints::PER_MATERIAL_INSTANCE, + extractUniforms(info.uib) }, + }); + + // FIXME: don't hardcode this + auto& uniforms = list[1].second; + uniforms.clear(); + uniforms.reserve(6); + uniforms.push_back({ + "objectUniforms.data[0].worldFromModelMatrix", + offsetof(PerRenderableUib, data[0].worldFromModelMatrix), 1, + UniformType::MAT4 }); + uniforms.push_back({ + "objectUniforms.data[0].worldFromModelNormalMatrix", + offsetof(PerRenderableUib, data[0].worldFromModelNormalMatrix), 1, + UniformType::MAT3 }); + uniforms.push_back({ + "objectUniforms.data[0].morphTargetCount", + offsetof(PerRenderableUib, data[0].morphTargetCount), 1, + UniformType::UINT }); + uniforms.push_back({ + "objectUniforms.data[0].flagsChannels", + offsetof(PerRenderableUib, data[0].flagsChannels), 1, + UniformType::UINT }); + uniforms.push_back({ + "objectUniforms.data[0].objectId", + offsetof(PerRenderableUib, data[0].objectId), 1, + UniformType::UINT }); + uniforms.push_back({ + "objectUniforms.data[0].userData", + offsetof(PerRenderableUib, data[0].userData), 1, + UniformType::FLOAT }); + + container.push(std::move(list)); + + using Container = utils::FixedCapacityVector>; + auto attributes = Container::with_capacity(sAttributeDatabase.size()); + for (auto const& attribute: sAttributeDatabase) { + std::string name("mesh_"); + name.append(attribute.name); + attributes.emplace_back(utils::CString{ name.data(), name.size() }, attribute.location); + } + container.push(std::move(attributes)); + } + + // TODO: currently, the feature level used is determined by the material because we + // don't have "feature level" variants. In other words, a feature level 0 material + // won't work with a feature level 1 engine. However, we do embed the feature level 1 + // meta-data, as it should. + if (info.featureLevel <= FeatureLevel::FEATURE_LEVEL_1) { // note: this chunk is only needed for OpenGL backends, which don't all support layout(binding=) FixedCapacityVector> list = { diff --git a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp index b3ebd9e0b5..bf16eb233f 100644 --- a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp +++ b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.cpp @@ -130,7 +130,7 @@ void MaterialSamplerBlockBindingChunk::flatten(Flattener& f) { f.writeUint8(utils::Enum::count()); UTILS_NOUNROLL for (size_t i = 0; i < utils::Enum::count(); i++) { - SamplerBindingPoints bindingPoint = (SamplerBindingPoints)i; + SamplerBindingPoints const bindingPoint = (SamplerBindingPoints)i; auto const& bindingInfo = mSamplerBindings.getSamplerGroupBindingInfo(bindingPoint); f.writeUint8(bindingInfo.bindingOffset); f.writeUint8((uint8_t)bindingInfo.shaderStageFlags); @@ -150,4 +150,42 @@ void MaterialSamplerBlockBindingChunk::flatten(Flattener& f) { assert_invariant(c == mSamplerBindings.getActiveSamplerCount()); } +// ------------------------------------------------------------------------------------------------ + +MaterialBindingUniformInfoChunk::MaterialBindingUniformInfoChunk(Container list) noexcept + : Chunk(ChunkType::MaterialBindingUniformInfo), + mBindingUniformInfo(std::move(list)) +{ +} + +void MaterialBindingUniformInfoChunk::flatten(Flattener& f) { + f.writeUint8(mBindingUniformInfo.size()); + for (auto const& [index, uniforms] : mBindingUniformInfo) { + f.writeUint8(uint8_t(index)); + f.writeUint8(uint8_t(uniforms.size())); + for (auto const& uniform: uniforms) { + f.writeString({ uniform.name.data(), uniform.name.size() }); + f.writeUint16(uniform.offset); + f.writeUint8(uniform.size); + f.writeUint8(uint8_t(uniform.type)); + } + } +} + +// ------------------------------------------------------------------------------------------------ + +MaterialAttributesInfoChunk::MaterialAttributesInfoChunk(Container list) noexcept + : Chunk(ChunkType::MaterialAttributeInfo), + mAttributeInfo(std::move(list)) +{ +} + +void MaterialAttributesInfoChunk::flatten(Flattener& f) { + f.writeUint8(mAttributeInfo.size()); + for (auto const& [attribute, location]: mAttributeInfo) { + f.writeString({ attribute.data(), attribute.size() }); + f.writeUint8(location); + } +} + } // namespace filamat diff --git a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h index aa287096d4..ba5f325234 100644 --- a/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h +++ b/libs/filamat/src/eiff/MaterialInterfaceBlockChunk.h @@ -21,6 +21,8 @@ #include +#include + #include namespace filament { @@ -87,15 +89,16 @@ private: // ------------------------------------------------------------------------------------------------ class MaterialUniformBlockBindingsChunk final : public Chunk { + using Container = utils::FixedCapacityVector< + std::pair>; public: - explicit MaterialUniformBlockBindingsChunk( - utils::FixedCapacityVector> list); + explicit MaterialUniformBlockBindingsChunk(Container list); ~MaterialUniformBlockBindingsChunk() final = default; private: void flatten(Flattener&) final; - utils::FixedCapacityVector> mBindingList; + Container mBindingList; }; // ------------------------------------------------------------------------------------------------ @@ -111,6 +114,35 @@ private: filament::SamplerBindingMap const& mSamplerBindings; }; +// ------------------------------------------------------------------------------------------------ + +class MaterialBindingUniformInfoChunk final : public Chunk { + using Container = FixedCapacityVector< + std::pair>; +public: + explicit MaterialBindingUniformInfoChunk(Container list) noexcept; + ~MaterialBindingUniformInfoChunk() final = default; + +private: + void flatten(Flattener &) final; + + Container mBindingUniformInfo; +}; + +// ------------------------------------------------------------------------------------------------ + +class MaterialAttributesInfoChunk final : public Chunk { + using Container = FixedCapacityVector>; +public: + explicit MaterialAttributesInfoChunk(Container list) noexcept; + ~MaterialAttributesInfoChunk() final = default; + +private: + void flatten(Flattener &) final; + + Container mAttributeInfo; +}; + } // namespace filamat #endif // TNT_FILAMAT_MAT_INTEFFACE_BLOCK_CHUNK_H diff --git a/libs/filamat/src/sca/GLSLTools.cpp b/libs/filamat/src/sca/GLSLTools.cpp index b7ac7815da..0ee77a55f2 100644 --- a/libs/filamat/src/sca/GLSLTools.cpp +++ b/libs/filamat/src/sca/GLSLTools.cpp @@ -381,7 +381,12 @@ std::pair GLSLTools::getShadingLanguageVersion(ShaderModel model, using FeatureLevel = filament::backend::FeatureLevel; switch (model) { case ShaderModel::MOBILE: - return { featureLevel >= FeatureLevel::FEATURE_LEVEL_2 ? 310 : 300, true }; + switch (featureLevel) { + case FeatureLevel::FEATURE_LEVEL_0: return { 100, true }; + case FeatureLevel::FEATURE_LEVEL_1: return { 300, true }; + case FeatureLevel::FEATURE_LEVEL_2: return { 310, true }; + case FeatureLevel::FEATURE_LEVEL_3: return { 310, true }; + } case ShaderModel::DESKTOP: return { featureLevel >= FeatureLevel::FEATURE_LEVEL_2 ? 430 : 410, false }; } diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index a792cfa6ee..0424b1e57a 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -130,15 +130,34 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade out << "#define FILAMENT_HAS_FEATURE_TEXTURE_GATHER\n"; } + if (material.featureLevel >= FeatureLevel::FEATURE_LEVEL_1) { + out << "#define FILAMENT_HAS_FEATURE_INSTANCING\n"; + } + if (stage == ShaderStage::VERTEX) { CodeGenerator::generateDefine(out, "FLIP_UV_ATTRIBUTE", material.flipUV); CodeGenerator::generateDefine(out, "LEGACY_MORPHING", material.useLegacyMorphing); } - if (stage == ShaderStage::VERTEX) { - generateDefine(out, "VARYING", "out"); - } else if (stage == ShaderStage::FRAGMENT) { - generateDefine(out, "VARYING", "in"); + if (mTargetLanguage == TargetLanguage::SPIRV || + mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) { + if (stage == ShaderStage::VERTEX) { + generateDefine(out, "VARYING", "out"); + } else if (stage == ShaderStage::FRAGMENT) { + generateDefine(out, "VARYING", "in"); + } + } else { + generateDefine(out, "VARYING", "varying"); + } + + if (mTargetLanguage == TargetLanguage::SPIRV && + mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + generateDefine(out, "texture2D", "texture"); + generateDefine(out, "textureCube", "texture"); + if (stage == ShaderStage::VERTEX) { + generateDefine(out, "texture2DLod", "textureLod"); + generateDefine(out, "textureCubeLod", "textureLod"); + } } auto getShadingDefine = [](Shading shading) -> const char* { @@ -162,8 +181,10 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade out << "precision " << precision << " float;\n"; out << "precision " << precision << " int;\n"; if (mShaderModel == ShaderModel::MOBILE) { - out << "precision lowp sampler2DArray;\n"; - out << "precision lowp sampler3D;\n"; + if (material.featureLevel >= FeatureLevel::FEATURE_LEVEL_1) { + out << "precision lowp sampler2DArray;\n"; + out << "precision lowp sampler3D;\n"; + } } // Filament-reserved specification constants (limited by CONFIG_MAX_RESERVED_SPEC_CONSTANTS) @@ -271,16 +292,16 @@ io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage if (stage == ShaderStage::VERTEX) { out << "\n#define VARIABLE_CUSTOM" << index << " " << name.c_str() << "\n"; out << "\n#define VARIABLE_CUSTOM_AT" << index << " variable_" << name.c_str() << "\n"; - out << "LAYOUT_LOCATION(" << index << ") out vec4 variable_" << name.c_str() << ";\n"; + out << "LAYOUT_LOCATION(" << index << ") VARYING vec4 variable_" << name.c_str() << ";\n"; } else if (stage == ShaderStage::FRAGMENT) { - out << "\nLAYOUT_LOCATION(" << index << ") in highp vec4 variable_" << name.c_str() << ";\n"; + out << "\nLAYOUT_LOCATION(" << index << ") VARYING highp vec4 variable_" << name.c_str() << ";\n"; } } return out; } io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage type, - const AttributeBitset& attributes, Interpolation interpolation) { + const AttributeBitset& attributes, Interpolation interpolation) const { auto const& attributeDatabase = MaterialBuilder::getAttributeDatabase(); @@ -294,12 +315,16 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t if (type == ShaderStage::VERTEX) { out << "\n"; - attributes.forEachSetBit([&out, &attributeDatabase](size_t i) { + attributes.forEachSetBit([&out, &attributeDatabase, this](size_t i) { auto const& attribute = attributeDatabase[i]; assert_invariant( i == attribute.location ); - out << "layout(location = " << size_t(attribute.location) << ") in " - << getTypeName(attribute.type) << " " - << attribute.getAttributeName() << ";\n"; + if (mTargetLanguage == TargetLanguage::SPIRV || + mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) { + out << "layout(location = " << size_t(attribute.location) << ") in "; + } else { + out << "attribute "; + } + out << getTypeName(attribute.type) << " " << attribute.getAttributeName() << ";\n"; }); } @@ -394,6 +419,57 @@ io::sstream& CodeGenerator::generateUniforms(io::sstream& out, ShaderStage stage return generateBufferInterfaceBlock(out, stage, +binding, uib); } +io::sstream& CodeGenerator::generateInterfaceFields(io::sstream& out, + FixedCapacityVector const& infos, + Precision defaultPrecision) const { + Precision const uniformPrecision = getDefaultUniformPrecision(); + + for (auto const& info : infos) { + if (mFeatureLevel < info.minFeatureLevel) { + continue; + } + char const* const type = getUniformTypeName(info); + char const* const precision = getUniformPrecisionQualifier(info.type, info.precision, + uniformPrecision, defaultPrecision); + out << " " << precision; + if (precision[0] != '\0') out << " "; + out << type << " " << info.name.c_str(); + if (info.isArray) { + if (info.sizeName.empty()) { + if (info.size) { + out << "[" << info.size << "]"; + } else { + out << "[]"; + } + } else { + out << "[" << info.sizeName.c_str() << "]"; + } + } + out << ";\n"; + } + return out; +} + +io::sstream& CodeGenerator::generateUboAsPlainUniforms(io::sstream& out, ShaderStage stage, + const BufferInterfaceBlock& uib) const { + + auto const& infos = uib.getFieldInfoList(); + + std::string blockName{ uib.getName() }; + std::string instanceName{ uib.getName() }; + blockName.front() = char(std::toupper((unsigned char)blockName.front())); + instanceName.front() = char(std::tolower((unsigned char)instanceName.front())); + + out << "\nstruct " << blockName << " {\n"; + + generateInterfaceFields(out, infos, Precision::DEFAULT); + + out << "};\n"; + out << "uniform " << blockName << " " << instanceName << ";\n"; + + return out; +} + io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, ShaderStage stage, uint32_t binding, const BufferInterfaceBlock& uib) const { auto const& infos = uib.getFieldInfoList(); @@ -401,14 +477,19 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade return out; } + if (mTargetLanguage == TargetLanguage::GLSL && + mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) { + // we need to generate a structure instead + assert_invariant(mTargetApi == TargetApi::OPENGL); + assert_invariant(uib.getTarget() == BufferInterfaceBlock::Target::UNIFORM); + return generateUboAsPlainUniforms(out, stage, uib); + } + std::string blockName{ uib.getName() }; std::string instanceName{ uib.getName() }; blockName.front() = char(std::toupper((unsigned char)blockName.front())); instanceName.front() = char(std::tolower((unsigned char)instanceName.front())); - Precision const uniformPrecision = getDefaultUniformPrecision(); - Precision const defaultPrecision = getDefaultPrecision(stage); - auto metalBufferBindingOffset = 0; switch (uib.getTarget()) { case BufferInterfaceBlock::Target::UNIFORM: @@ -477,26 +558,8 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade out << "{\n"; - for (auto const& info : infos) { - char const* const type = getUniformTypeName(info); - char const* const precision = getUniformPrecisionQualifier(info.type, info.precision, - uniformPrecision, defaultPrecision); - out << " " << precision; - if (precision[0] != '\0') out << " "; - out << type << " " << info.name.c_str(); - if (info.isArray) { - if (info.sizeName.empty()) { - if (info.size) { - out << "[" << info.size << "]"; - } else { - out << "[]"; - } - } else { - out << "[" << info.sizeName.c_str() << "]"; - } - } - out << ";\n"; - } + generateInterfaceFields(out, infos, getDefaultPrecision(stage)); + out << "} " << instanceName << ";\n"; return out; diff --git a/libs/filamat/src/shaders/CodeGenerator.h b/libs/filamat/src/shaders/CodeGenerator.h index 064b02ee72..1ddd910a4b 100644 --- a/libs/filamat/src/shaders/CodeGenerator.h +++ b/libs/filamat/src/shaders/CodeGenerator.h @@ -17,30 +17,30 @@ #ifndef TNT_FILAMENT_CODEGENERATOR_H #define TNT_FILAMENT_CODEGENERATOR_H -#include -#include -#include -#include #include "MaterialInfo.h" -#include -#include - #include + #include #include #include #include #include +#include #include +#include +#include +#include #include -#include -#include "private/filament/EngineEnums.h" +#include +#include +#include +#include namespace filamat { @@ -106,8 +106,8 @@ public: const utils::CString& name, size_t index); // generate declarations for non-custom "in" variables - static utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderStage type, - const filament::AttributeBitset& attributes, filament::Interpolation interpolation); + utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderStage type, + const filament::AttributeBitset& attributes, filament::Interpolation interpolation) const; static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage type); // generate declarations for custom output variables @@ -173,6 +173,13 @@ private: filament::backend::Precision getDefaultPrecision(ShaderStage stage) const; filament::backend::Precision getDefaultUniformPrecision() const; + utils::io::sstream& generateInterfaceFields(utils::io::sstream& out, + utils::FixedCapacityVector const& infos, + filament::backend::Precision defaultPrecision) const; + + utils::io::sstream& generateUboAsPlainUniforms(utils::io::sstream& out, ShaderStage stage, + const filament::BufferInterfaceBlock& uib) const; + static const char* getUniformPrecisionQualifier(filament::backend::UniformType type, filament::backend::Precision precision, filament::backend::Precision uniformPrecision, diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index bf3f52344c..217aaf44a3 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -404,7 +404,7 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, attributes.set(VertexAttribute::MORPH_TANGENTS_3); } } - CodeGenerator::generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation); + cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation); CodeGenerator::generateCommonTypes(vs, ShaderStage::VERTEX); @@ -502,7 +502,7 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, generateSurfaceMaterialVariantProperties(fs, mProperties, mDefines); - CodeGenerator::generateShaderInputs(fs, ShaderStage::FRAGMENT, + cg.generateShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation); CodeGenerator::generateCommonTypes(fs, ShaderStage::FRAGMENT); @@ -541,9 +541,11 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, CodeGenerator::generateSeparator(fs); - cg.generateSamplers(fs, SamplerBindingPoints::PER_VIEW, - material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_VIEW), - SibGenerator::getPerViewSib(variant)); + if (material.featureLevel >= FeatureLevel::FEATURE_LEVEL_1) { // FIXME: generate only what we need + cg.generateSamplers(fs, SamplerBindingPoints::PER_VIEW, + material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_VIEW), + SibGenerator::getPerViewSib(variant)); + } cg.generateSamplers(fs, SamplerBindingPoints::PER_MATERIAL_INSTANCE, material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_MATERIAL_INSTANCE), @@ -556,7 +558,10 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, CodeGenerator::generateGetters(fs, ShaderStage::FRAGMENT); CodeGenerator::generateCommonMaterial(fs, ShaderStage::FRAGMENT); CodeGenerator::generateParameters(fs, ShaderStage::FRAGMENT); - CodeGenerator::generateFog(fs, ShaderStage::FRAGMENT); + + if (filament::Variant::isFogVariant(variant)) { + CodeGenerator::generateFog(fs, ShaderStage::FRAGMENT); + } // shading model if (filament::Variant::isValidDepthVariant(variant)) { diff --git a/libs/filamat/src/shaders/UibGenerator.cpp b/libs/filamat/src/shaders/UibGenerator.cpp index 55d50b29ea..0bdae92f01 100644 --- a/libs/filamat/src/shaders/UibGenerator.cpp +++ b/libs/filamat/src/shaders/UibGenerator.cpp @@ -35,37 +35,37 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept { static BufferInterfaceBlock const uib = BufferInterfaceBlock::Builder() .name(PerViewUib::_name) .add({ - { "viewFromWorldMatrix", 0, Type::MAT4, Precision::HIGH }, - { "worldFromViewMatrix", 0, Type::MAT4, Precision::HIGH }, - { "clipFromViewMatrix", 0, Type::MAT4, Precision::HIGH }, - { "viewFromClipMatrix", 0, Type::MAT4, Precision::HIGH }, - { "clipFromWorldMatrix", 0, Type::MAT4, Precision::HIGH }, - { "worldFromClipMatrix", 0, Type::MAT4, Precision::HIGH }, - { "userWorldFromWorldMatrix",0,Type::MAT4, Precision::HIGH }, - { "clipTransform", 0, Type::FLOAT4, Precision::HIGH }, + { "viewFromWorldMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "worldFromViewMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "clipFromViewMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "viewFromClipMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "clipFromWorldMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "worldFromClipMatrix", 0, Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "userWorldFromWorldMatrix",0,Type::MAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "clipTransform", 0, Type::FLOAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, - { "clipControl", 0, Type::FLOAT2 }, - { "time", 0, Type::FLOAT, Precision::HIGH }, - { "temporalNoise", 0, Type::FLOAT, Precision::HIGH }, - { "userTime", 0, Type::FLOAT4, Precision::HIGH }, + { "clipControl", 0, Type::FLOAT2, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "time", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "temporalNoise", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "userTime", 0, Type::FLOAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, // ------------------------------------------------------------------------------------ // values below should only be accessed in surface materials // ------------------------------------------------------------------------------------ - { "resolution", 0, Type::FLOAT4, Precision::HIGH }, - { "logicalViewportScale", 0, Type::FLOAT2, Precision::HIGH }, - { "logicalViewportOffset", 0, Type::FLOAT2, Precision::HIGH }, + { "resolution", 0, Type::FLOAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "logicalViewportScale", 0, Type::FLOAT2, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "logicalViewportOffset", 0, Type::FLOAT2, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, - { "lodBias", 0, Type::FLOAT }, - { "refractionLodOffset", 0, Type::FLOAT }, + { "lodBias", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "refractionLodOffset", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, - { "oneOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH }, - { "nearOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH }, - { "cameraFar", 0, Type::FLOAT }, - { "exposure", 0, Type::FLOAT, Precision::HIGH }, // high precision to work around #3602 (qualcom), - { "ev100", 0, Type::FLOAT }, - { "needsAlphaChannel", 0, Type::FLOAT }, + { "oneOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "nearOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "cameraFar", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "exposure", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, // high precision to work around #3602 (qualcom), + { "ev100", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "needsAlphaChannel", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, // AO { "aoSamplingQualityAndEdgeDistance", 0, Type::FLOAT }, @@ -81,17 +81,17 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept { { "lightChannels", 0, Type::INT }, { "froxelCountXY", 0, Type::FLOAT2 }, - { "iblLuminance", 0, Type::FLOAT }, - { "iblRoughnessOneLevel", 0, Type::FLOAT }, + { "iblLuminance", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "iblRoughnessOneLevel", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, { "iblSH", 9, Type::FLOAT3 }, // ------------------------------------------------------------------------------------ // Directional Lighting [variant: DIR] // ------------------------------------------------------------------------------------ - { "lightDirection", 0, Type::FLOAT3 }, + { "lightDirection", 0, Type::FLOAT3, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, { "padding0", 0, Type::FLOAT }, - { "lightColorIntensity", 0, Type::FLOAT4 }, - { "sun", 0, Type::FLOAT4 }, + { "lightColorIntensity", 0, Type::FLOAT4, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "sun", 0, Type::FLOAT4, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, { "lightFarAttenuationParams", 0, Type::FLOAT2 }, // ------------------------------------------------------------------------------------ @@ -117,16 +117,16 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept { // ------------------------------------------------------------------------------------ // Fog [variant: FOG] // ------------------------------------------------------------------------------------ - { "fogDensity", 0, Type::FLOAT3,Precision::HIGH }, - { "fogStart", 0, Type::FLOAT, Precision::HIGH }, - { "fogMaxOpacity", 0, Type::FLOAT }, - { "fogHeight", 0, Type::FLOAT, Precision::HIGH }, - { "fogHeightFalloff", 0, Type::FLOAT, Precision::HIGH }, - { "fogCutOffDistance", 0, Type::FLOAT, Precision::HIGH }, - { "fogColor", 0, Type::FLOAT3 }, - { "fogColorFromIbl", 0, Type::FLOAT }, - { "fogInscatteringStart", 0, Type::FLOAT, Precision::HIGH }, - { "fogInscatteringSize", 0, Type::FLOAT }, + { "fogDensity", 0, Type::FLOAT3,Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogStart", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogMaxOpacity", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogHeight", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogHeightFalloff", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogCutOffDistance", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogColor", 0, Type::FLOAT3, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogColorFromIbl", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogInscatteringStart", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, + { "fogInscatteringSize", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }, { "fogReserved1", 0, Type::FLOAT }, { "fogReserved2", 0, Type::FLOAT }, @@ -143,7 +143,7 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept { // -------------------------------------------------------------------------------------------- // user defined global variables // -------------------------------------------------------------------------------------------- - { "custom", 4, Type::FLOAT4, Precision::HIGH }, + { "custom", 4, Type::FLOAT4, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 }, // bring PerViewUib to 2 KiB { "reserved", sizeof(PerViewUib::reserved)/16, Type::FLOAT4 } @@ -156,7 +156,7 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept { BufferInterfaceBlock const& UibGenerator::getPerRenderableUib() noexcept { static BufferInterfaceBlock const uib = BufferInterfaceBlock::Builder() .name(PerRenderableUib::_name) - .add({{ "data", CONFIG_MAX_INSTANCES, BufferInterfaceBlock::Type::STRUCT, {}, + .add({{ "data", CONFIG_MAX_INSTANCES, BufferInterfaceBlock::Type::STRUCT, {}, {}, "PerRenderableData", sizeof(PerRenderableData), "CONFIG_MAX_INSTANCES" }}) .build(); return uib; @@ -175,7 +175,7 @@ BufferInterfaceBlock const& UibGenerator::getShadowUib() noexcept { static BufferInterfaceBlock const uib = BufferInterfaceBlock::Builder() .name(ShadowUib::_name) .add({{ "shadows", CONFIG_MAX_SHADOWMAPS, - BufferInterfaceBlock::Type::STRUCT, {}, + BufferInterfaceBlock::Type::STRUCT, {}, {}, "ShadowData", sizeof(ShadowUib::ShadowData) }}) .build(); return uib; @@ -185,7 +185,7 @@ BufferInterfaceBlock const& UibGenerator::getPerRenderableBonesUib() noexcept { static BufferInterfaceBlock const uib = BufferInterfaceBlock::Builder() .name(PerRenderableBoneUib::_name) .add({{ "bones", CONFIG_MAX_BONE_COUNT, - BufferInterfaceBlock::Type::STRUCT, {}, + BufferInterfaceBlock::Type::STRUCT, {}, {}, "BoneData", sizeof(PerRenderableBoneUib::BoneData) }}) .build(); return uib; diff --git a/shaders/src/common_instancing.glsl b/shaders/src/common_instancing.glsl index de80378122..db68b86ca5 100644 --- a/shaders/src/common_instancing.glsl +++ b/shaders/src/common_instancing.glsl @@ -5,6 +5,7 @@ PerRenderableData object_uniforms; void initInstanceUniforms(out PerRenderableData p) { +#if defined(FILAMENT_HAS_FEATURE_INSTANCING) // We're copying each field separately to workaround an issue in some Adreno drivers // that fail on non-const array access in a UBO. Accessing the fields works however. // e.g.: this fails `p = objectUniforms.data[instance_index];` @@ -14,19 +15,25 @@ void initInstanceUniforms(out PerRenderableData p) { p.flagsChannels = objectUniforms.data[instance_index].flagsChannels; p.objectId = objectUniforms.data[instance_index].objectId; p.userData = objectUniforms.data[instance_index].userData; +#else + p.worldFromModelMatrix = objectUniforms.data[0].worldFromModelMatrix; + p.worldFromModelNormalMatrix = objectUniforms.data[0].worldFromModelNormalMatrix; + p.morphTargetCount = objectUniforms.data[0].morphTargetCount; + p.flagsChannels = objectUniforms.data[0].flagsChannels; + p.objectId = objectUniforms.data[0].objectId; + p.userData = objectUniforms.data[0].userData; +#endif } void initObjectUniforms(out PerRenderableData p) { -#if defined(MATERIAL_HAS_INSTANCES) +#if defined(FILAMENT_HAS_FEATURE_INSTANCING) && defined(MATERIAL_HAS_INSTANCES) if ((objectUniforms.data[0].flagsChannels & FILAMENT_OBJECT_INSTANCE_BUFFER_BIT) != 0) { // the object has an instance buffer initInstanceUniforms(p); return; } - // the material manages instancing, all instances share the same uniform block. p = objectUniforms.data[0]; - #else // automatic instancing was used, each instance has its own uniform block. initInstanceUniforms(p); @@ -37,9 +44,11 @@ void initObjectUniforms(out PerRenderableData p) { // Instance access //------------------------------------------------------------------------------ +#if defined(FILAMENT_HAS_FEATURE_INSTANCING) #if defined(MATERIAL_HAS_INSTANCES) /** @public-api */ int getInstanceIndex() { return instance_index; } #endif +#endif diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index 3026bf78f1..32da5b7571 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -21,6 +21,7 @@ float getObjectUserData() { // Attributes access //------------------------------------------------------------------------------ +#if __VERSION__ >= 300 /** @public-api */ int getVertexIndex() { #if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) @@ -29,6 +30,7 @@ int getVertexIndex() { return gl_VertexID; #endif } +#endif #if defined(VARIANT_HAS_SKINNING_OR_MORPHING) vec3 mulBoneNormal(vec3 n, uint i) { diff --git a/shaders/src/main.fs b/shaders/src/main.fs index fe1ee597b2..06aa0bf523 100644 --- a/shaders/src/main.fs +++ b/shaders/src/main.fs @@ -1,4 +1,8 @@ +#if __VERSION__ == 100 +vec4 fragColor; +#else layout(location = 0) out vec4 fragColor; +#endif #if defined(MATERIAL_HAS_POST_LIGHTING_COLOR) void blendPostLightingColor(const MaterialInputs material, inout vec4 color) { @@ -42,4 +46,8 @@ void main() { highp vec3 view = getWorldPosition() - getWorldCameraPosition(); fragColor = fog(fragColor, view); #endif + +#if __VERSION__ == 100 + gl_FragData[0] = fragColor; +#endif } diff --git a/shaders/src/main.vs b/shaders/src/main.vs index 053813f6fb..9debbcd63d 100644 --- a/shaders/src/main.vs +++ b/shaders/src/main.vs @@ -7,10 +7,12 @@ */ void main() { -#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) +#if defined(FILAMENT_HAS_FEATURE_INSTANCING) +# if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) instance_index = gl_InstanceIndex; -#else +# else instance_index = gl_InstanceID; +# endif #endif initObjectUniforms(object_uniforms); diff --git a/shaders/src/varyings.glsl b/shaders/src/varyings.glsl index 91ecade3fc..234d880825 100644 --- a/shaders/src/varyings.glsl +++ b/shaders/src/varyings.glsl @@ -13,7 +13,9 @@ LAYOUT_LOCATION(6) SHADING_INTERPOLATION VARYING mediump vec4 vertex_worldTangen LAYOUT_LOCATION(7) VARYING highp vec4 vertex_position; +#if defined(FILAMENT_HAS_FEATURE_INSTANCING) LAYOUT_LOCATION(8) flat VARYING highp int instance_index; +#endif #if defined(HAS_ATTRIBUTE_COLOR) LAYOUT_LOCATION(9) VARYING mediump vec4 vertex_color; diff --git a/tools/matc/src/matc/CommandlineConfig.cpp b/tools/matc/src/matc/CommandlineConfig.cpp index 5d18fd46a6..2705d95050 100644 --- a/tools/matc/src/matc/CommandlineConfig.cpp +++ b/tools/matc/src/matc/CommandlineConfig.cpp @@ -256,6 +256,7 @@ bool CommandlineConfig::parse() { auto featureLevel = filament::backend::FeatureLevel(std::atoi(arg.c_str())); mFeatureLevel = filament::backend::FeatureLevel::FEATURE_LEVEL_3; switch (featureLevel) { + case filament::backend::FeatureLevel::FEATURE_LEVEL_0: case filament::backend::FeatureLevel::FEATURE_LEVEL_1: case filament::backend::FeatureLevel::FEATURE_LEVEL_2: case filament::backend::FeatureLevel::FEATURE_LEVEL_3: diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp index 8a5c823926..c6f0192cd7 100644 --- a/tools/matc/src/matc/ParametersProcessor.cpp +++ b/tools/matc/src/matc/ParametersProcessor.cpp @@ -748,7 +748,9 @@ static bool processFeatureLevel(MaterialBuilder& builder, const JsonishValue& va using filament::backend::FeatureLevel; JsonishNumber const* const number = value.toJsonNumber(); FeatureLevel featureLevel; - if (number->getFloat() == 1.0f) { + if (number->getFloat() == 0.0f) { + featureLevel = FeatureLevel::FEATURE_LEVEL_0; + } else if (number->getFloat() == 1.0f) { featureLevel = FeatureLevel::FEATURE_LEVEL_1; } else if (number->getFloat() == 2.0f) { featureLevel = FeatureLevel::FEATURE_LEVEL_2;