Compare commits

...

37 Commits

Author SHA1 Message Date
Benjamin Doherty
cc9e05e711 Merge branch 'rc/1.9.9' into release 2020-11-16 12:34:13 -08:00
Benjamin Doherty
419d68d4db Update RELEASE_NOTES for 1.9.9 2020-11-16 12:17:02 -08:00
Philip Rideout
8450232448 Improve the "unbound texture" warnings.
With Vulkan, this warning would sometimes be a false positive. It could
trigger for internal samplers like `ssao` and `structure`, even though
they were not declared in SPIR-V.

With OpenGL, this warning would never be a false positive because it has
the luxury of calling `glGetUniformLocation`.

This adds a private attribute to our samplers called `strict` that
indicates whether or not a sampler should always have a bound texture.
For now the only strict samplers are the custom ones declared in the
user's material.

At some point I think we should consider adding `spirv-reflect` to our
tree to help with problems like this.
2020-11-12 16:21:13 -08:00
Philip Rideout
cc51726590 Vulkan: improve robustness by providing 1x1 fallback. 2020-11-12 10:36:13 -08:00
Philip Rideout
318e22af51 Fix clear behavior with RenderTarget API.
This fixes a bug seen with client applications that use ClearOptions
instead of Skybox, and one or more offscreen RenderTarget objects.
These apps would see junk pixels because Filament would only clear the
first render target in the frame.

The fix is to factor some the flag-setting logic in `beginFrame()` into
a private method, and call this method from `render()` each time
the user-level RenderTarget has been changed.

I wrote a simple C++ demo to reproduce the issue and to verify that
this fix works.
2020-11-11 09:25:36 -08:00
Philip Rideout
68ac87dc24 NOOP backend should not care about GLSL vs SPIRV.
This fixes errors that would occur when using the NOOP backend with
materials that were built without OpenGL support.
2020-11-10 15:44:01 -08:00
Benjamin Doherty
acb8f00075 Bump version to 1.9.9 2020-11-09 09:32:55 -08:00
Benjamin Doherty
06d9183aaa Merge branch 'rc/1.9.8' into release 2020-11-09 09:28:58 -08:00
Benjamin Doherty
75af25419d Update RELEASE_NOTES for 1.9.8 2020-11-09 09:26:27 -08:00
Benjamin Doherty
f6b90d2a31 Bump version to 1.9.8 2020-11-09 09:21:36 -08:00
Philip Rideout
a3822f4af0 Fix FENCE_WAIT_FOR_EVER in Linux.
The number of infinite nanoseconds was negative because we asked
chrono for a signed integer, so "wait forever" really meant "do not
wait at all".
2020-11-02 16:12:53 -08:00
Benjamin Doherty
bcdad769ff Merge branch 'rc/1.9.7' into release 2020-11-02 11:03:57 -07:00
Benjamin Doherty
be4fb4fdbb Update RELEASE_NOTES for 1.9.7 2020-11-02 10:59:19 -07:00
Benjamin Doherty
65394f6301 Bump version to 1.9.7 2020-10-26 11:34:20 -06:00
Benjamin Doherty
b0beee03bc Merge branch 'rc/1.9.6' into release 2020-10-26 11:29:45 -06:00
Benjamin Doherty
fe1de41b8e Update RELEASE_NOTES for 1.9.6 2020-10-26 11:25:31 -06:00
Benjamin Doherty
a37b431e87 Bump version to 1.9.6 2020-10-19 11:55:13 -06:00
Benjamin Doherty
98107016b9 Merge branch 'rc/1.9.5' into release 2020-10-19 11:51:30 -06:00
Benjamin Doherty
8bccfc2863 Update RELEASE_NOTES for 1.9.5 2020-10-19 11:49:05 -06:00
Benjamin Doherty
f54a0a3452 Fix CocoaPod version 2020-10-13 15:15:02 -06:00
Benjamin Doherty
6778ab0624 Fix CocoaPod version 2020-10-13 15:09:59 -06:00
Benjamin Doherty
269d636785 Bump version to 1.9.5 2020-10-12 12:03:29 -06:00
Benjamin Doherty
39862c91ce Merge branch 'rc/1.9.4' into release 2020-10-12 11:56:24 -06:00
Benjamin Doherty
523f4026b4 Update RELEASE_NOTES for 1.9.4 2020-10-12 11:52:01 -06:00
Benjamin Doherty
a6bf162431 Bump version to 1.9.4 2020-10-07 16:06:23 -06:00
Benjamin Doherty
826e8d181c Merge branch 'rc/1.9.3' into release 2020-10-05 11:36:16 -06:00
Benjamin Doherty
16dfadbba0 Update RELEASE_NOTES for 1.9.3 2020-10-05 11:29:36 -06:00
Benjamin Doherty
5cbb97551f Bump version to 1.9.3 2020-09-28 11:40:31 -06:00
Benjamin Doherty
defee767c3 Merge branch 'rc/1.9.2' into release 2020-09-28 11:27:47 -06:00
Benjamin Doherty
9560318521 Update RELEASE_NOTES for 1.9.2 2020-09-28 11:26:21 -06:00
Benjamin Doherty
ef09feb048 Bump version to 1.9.2 2020-09-21 11:16:53 -06:00
Benjamin Doherty
39f323fe09 Merge branch 'rc/1.9.1' into release 2020-09-21 11:00:07 -06:00
Benjamin Doherty
11b95304ea Merge branch 'release' into rc/1.9.1 2020-09-21 10:59:52 -06:00
Benjamin Doherty
b7c30a7916 Update RELEASE_NOTES for 1.9.1 2020-09-21 10:59:06 -06:00
Benjamin Doherty
4cae48fc77 Bump version to 1.9.1 2020-09-14 11:51:36 -07:00
Benjamin Doherty
d1a93f0557 Update release notes for 1.9.0 2020-09-14 10:54:28 -07:00
Benjamin Doherty
b93059fad7 Bump version to 1.9.0 2020-09-08 10:47:23 -07:00
14 changed files with 117 additions and 61 deletions

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.9.8'
implementation 'com.google.android.filament:filament-android:1.9.9'
}
```
@@ -63,7 +63,7 @@ A much smaller alternative to `filamat-android` that can only generate OpenGL sh
iOS projects can use CocoaPods to install the latest release:
```
pod 'Filament', '~> 1.9.8'
pod 'Filament', '~> 1.9.9'
```
### Snapshots

View File

@@ -7,6 +7,13 @@ A new header is inserted each time a *tag* is created.
## v1.9.9
- Vulkan: internal robustness improvements
- Metal: Support CVPixelBuffer SwapChains
- Metal: Support copyFrame
- Fix clear behavior with RenderTarget API.
- Fix GetRefractionMode JNI binding
- Additional fixes for Fence bug
## v1.9.8
- Fix a few Fence-related bugs

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.9.8
VERSION_NAME=1.9.9
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -43,7 +43,8 @@ public:
struct Sampler {
utils::CString name = {}; // name of the sampler in the shader
size_t binding = 0; // binding point of the sampler in the shader
uint16_t binding = 0; // binding point of the sampler in the shader
bool strict = false; // if true, this sampler must always have a bound texture
};
using SamplerGroupInfo = std::array<std::vector<Sampler>, SAMPLER_BINDING_COUNT>;

View File

@@ -215,6 +215,7 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gl) noexcept {
Handle<HwTexture> th = samplers[index].t;
if (UTILS_UNLIKELY(!th)) {
#ifndef NDEBUG
slog.w << "In material " << name.c_str() << ": ";
slog.w << "no texture bound to unit " << +index << io::endl;
#endif
continue;

View File

@@ -957,5 +957,14 @@ void blitColor(VulkanContext* context, const VulkanRenderTarget* dstTarget,
}
}
void createEmptyTexture(VulkanContext& context, VulkanStagePool& stagePool) {
context.emptyTexture = new VulkanTexture(context, SamplerType::SAMPLER_2D, 1,
TextureFormat::RGBA8, 1, 1, 1, 1,
TextureUsage::DEFAULT | TextureUsage::COLOR_ATTACHMENT, stagePool);
uint32_t black = 0;
PixelBufferDescriptor pbd(&black, 4, PixelDataFormat::RGBA, PixelDataType::UBYTE);
context.emptyTexture->update2DImage(pbd, 1, 1, 0);
}
} // namespace filament
} // namespace backend

View File

@@ -50,6 +50,7 @@ constexpr static const int VK_REQUIRED_VERSION_MINOR = 0;
struct VulkanRenderTarget;
struct VulkanSurfaceContext;
struct VulkanTexture;
class VulkanStagePool;
// This wrapper exists so that we can use shared_ptr to implement shared ownership for low-level
// Vulkan fences.
@@ -111,6 +112,7 @@ struct VulkanContext {
VkViewport viewport;
VkFormat finalDepthFormat;
VmaAllocator allocator;
VulkanTexture* emptyTexture = nullptr;
// The work context is used for activities unrelated to the swap chain or draw calls, such as
// uploads, blits, and transitions.
@@ -176,6 +178,7 @@ VkCommandBuffer acquireWorkCommandBuffer(VulkanContext& context);
void flushWorkCommandBuffer(VulkanContext& context);
void createFinalDepthBuffer(VulkanContext& context, VulkanSurfaceContext& sc, VkFormat depthFormat);
VkImageLayout getTextureLayout(TextureUsage usage);
void createEmptyTexture(VulkanContext& context, VulkanStagePool& stagePool);
void blitDepth(VulkanContext* context, const VulkanRenderTarget* dstTarget,
const VkOffset3D dstRect[2], const VulkanRenderTarget* srcTarget,

View File

@@ -195,6 +195,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform,
// Initialize device and graphicsQueue.
createLogicalDevice(mContext);
mBinder.setDevice(mContext.device);
createEmptyTexture(mContext, mStagePool);
// Choose a depth format that meets our requirements. Take care not to include stencil formats
// just yet, since that would require a corollary change to the "aspect" flags for the VkImage.
@@ -247,6 +248,9 @@ void VulkanDriver::terminate() {
// Flush the work command buffer.
acquireWorkCommandBuffer(mContext);
delete mContext.emptyTexture;
mDisposer.release(mContext.work.resources);
// Allow the stage pool and disposer to clean up.
@@ -1592,14 +1596,28 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
const SamplerGroup::Sampler* boundSampler = sb->getSamplers() + samplerIdx;
samplerIdx++;
if (!boundSampler->t) {
continue;
// Note that we always use a 2D texture for the fallback texture, which might not be
// appropriate. The fallback improves robustness but does not guarantee 100% success.
// It can be argued that clients are being malfeasant here anyway, since Vulkan does
// not allow sampling from a non-bound texture.
const VulkanTexture* texture;
if (UTILS_UNLIKELY(!boundSampler->t)) {
if (!sampler.strict) {
continue;
}
utils::slog.w << "No texture bound to '" << sampler.name.c_str() << "'";
#ifndef NDEBUG
utils::slog.w << " in material '" << program->name.c_str() << "'";
#endif
utils::slog.w << " at binding point " << +bindingPoint << utils::io::endl;
texture = mContext.emptyTexture;
} else {
texture = handle_const_cast<VulkanTexture>(mHandleMap, boundSampler->t);
mDisposer.acquire(texture, commands->resources);
}
const SamplerParams& samplerParams = boundSampler->s;
VkSampler vksampler = mSamplerCache.getSampler(samplerParams);
const auto* texture = handle_const_cast<VulkanTexture>(mHandleMap, boundSampler->t);
mDisposer.acquire(texture, commands->resources);
mBinder.bindSampler(bindingPoint, {
.sampler = vksampler,

View File

@@ -44,6 +44,34 @@ namespace filament {
using namespace backend;
static MaterialParser* createParser(Backend backend, const void* data, size_t size) {
MaterialParser* materialParser = new MaterialParser(backend, data, size);
MaterialParser::ParseResult materialResult = materialParser->parse();
if (backend == Backend::NOOP) {
return materialParser;
}
if (!ASSERT_POSTCONDITION_NON_FATAL(materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND,
"the material was not built for the %s backend\n", backendToString(backend))) {
return nullptr;
}
if (!ASSERT_POSTCONDITION_NON_FATAL(materialResult == MaterialParser::ParseResult::SUCCESS,
"could not parse the material package")) {
return nullptr;
}
uint32_t version = 0;
materialParser->getMaterialVersion(&version);
ASSERT_PRECONDITION(version == MATERIAL_VERSION, "Material version mismatch. Expected %d but "
"received %d.", MATERIAL_VERSION, version);
assert(backend != Backend::DEFAULT && "Default backend has not been resolved.");
return materialParser;
}
struct Material::BuilderDetails {
const void* mPayload = nullptr;
@@ -71,7 +99,7 @@ Material::Builder& Material::Builder::package(const void* payload, size_t size)
}
Material* Material::Builder::build(Engine& engine) {
MaterialParser* materialParser = FMaterial::createParser(
MaterialParser* materialParser = createParser(
upcast(engine).getBackend(), mImpl->mPayload, mImpl->mSize);
uint32_t v = 0;
@@ -79,15 +107,15 @@ Material* Material::Builder::build(Engine& engine) {
utils::bitset32 shaderModels;
shaderModels.setValue(v);
backend::ShaderModel shaderModel = upcast(engine).getDriver().getShaderModel();
ShaderModel shaderModel = upcast(engine).getDriver().getShaderModel();
if (!shaderModels.test(static_cast<uint32_t>(shaderModel))) {
CString name;
materialParser->getName(&name);
slog.e << "The material '" << name.c_str_safe() << "' was not built for ";
switch (shaderModel) {
case backend::ShaderModel::GL_ES_30: slog.e << "mobile.\n"; break;
case backend::ShaderModel::GL_CORE_41: slog.e << "desktop.\n"; break;
case backend::ShaderModel::UNKNOWN: /* should never happen */ break;
case ShaderModel::GL_ES_30: slog.e << "mobile.\n"; break;
case ShaderModel::GL_CORE_41: slog.e << "desktop.\n"; break;
case ShaderModel::UNKNOWN: /* should never happen */ break;
}
slog.e << "Compiled material contains shader models 0x"
<< io::hex << shaderModels.getValue() << io::dec << "." << io::endl;
@@ -123,7 +151,8 @@ static void addSamplerGroup(Program& pb, uint8_t bindingPoint, SamplerInterfaceB
uint8_t binding = 0;
UTILS_UNUSED bool ok = map.getSamplerBinding(bindingPoint, (uint8_t)i, &binding);
assert(ok);
samplers[i] = { std::move(uniformName), binding };
const bool strict = (bindingPoint == filament::BindingPoints::PER_MATERIAL_INSTANCE);
samplers[i] = { std::move(uniformName), binding, strict };
}
pb.setSamplerGroup(bindingPoint, samplers.data(), samplers.size());
}
@@ -311,7 +340,7 @@ UniformInterfaceBlock::UniformInfo const* FMaterial::reflect(
return p == list.end() ? nullptr : &static_cast<UniformInterfaceBlock::UniformInfo const&>(*p);
}
backend::Handle<backend::HwProgram> FMaterial::getProgramSlow(uint8_t variantKey) const noexcept {
Handle<HwProgram> FMaterial::getProgramSlow(uint8_t variantKey) const noexcept {
switch (getMaterialDomain()) {
case MaterialDomain::SURFACE:
return getSurfaceProgramSlow(variantKey);
@@ -321,7 +350,7 @@ backend::Handle<backend::HwProgram> FMaterial::getProgramSlow(uint8_t variantKey
}
}
backend::Handle<backend::HwProgram> FMaterial::getSurfaceProgramSlow(uint8_t variantKey)
Handle<HwProgram> FMaterial::getSurfaceProgramSlow(uint8_t variantKey)
const noexcept {
// filterVariant() has already been applied in generateCommands(), shouldn't be needed here
// if we're unlit, we don't have any bits that correspond to lit materials
@@ -351,7 +380,7 @@ backend::Handle<backend::HwProgram> FMaterial::getSurfaceProgramSlow(uint8_t var
return createAndCacheProgram(std::move(pb), variantKey);
}
backend::Handle<backend::HwProgram> FMaterial::getPostProcessProgramSlow(uint8_t variantKey)
Handle<HwProgram> FMaterial::getPostProcessProgramSlow(uint8_t variantKey)
const noexcept {
Program pb = getProgramBuilderWithVariants(variantKey, variantKey, variantKey);
@@ -369,6 +398,7 @@ Program FMaterial::getProgramBuilderWithVariants(
uint8_t vertexVariantKey,
uint8_t fragmentVariantKey) const noexcept {
const ShaderModel sm = mEngine.getDriver().getShaderModel();
const bool isNoop = mEngine.getBackend() == Backend::NOOP;
/*
* Vertex shader
@@ -379,7 +409,7 @@ Program FMaterial::getProgramBuilderWithVariants(
UTILS_UNUSED_IN_RELEASE bool vsOK = mMaterialParser->getShader(vsBuilder, sm,
vertexVariantKey, ShaderType::VERTEX);
ASSERT_POSTCONDITION(vsOK && vsBuilder.size() > 0,
ASSERT_POSTCONDITION(isNoop || (vsOK && vsBuilder.size() > 0),
"The material '%s' has not been compiled to include the required "
"GLSL or SPIR-V chunks for the vertex shader (variant=0x%x, filtered=0x%x).",
mName.c_str(), variantKey, vertexVariantKey);
@@ -393,7 +423,7 @@ Program FMaterial::getProgramBuilderWithVariants(
UTILS_UNUSED_IN_RELEASE bool fsOK = mMaterialParser->getShader(fsBuilder, sm,
fragmentVariantKey, ShaderType::FRAGMENT);
ASSERT_POSTCONDITION(fsOK && fsBuilder.size() > 0,
ASSERT_POSTCONDITION(isNoop || (fsOK && fsBuilder.size() > 0),
"The material '%s' has not been compiled to include the required "
"GLSL or SPIR-V chunks for the fragment shader (variant=0x%x, filterer=0x%x).",
mName.c_str(), variantKey, fragmentVariantKey);
@@ -405,7 +435,7 @@ Program FMaterial::getProgramBuilderWithVariants(
return pb;
}
backend::Handle<backend::HwProgram> FMaterial::createAndCacheProgram(Program&& p,
Handle<HwProgram> FMaterial::createAndCacheProgram(Program&& p,
uint8_t variantKey) const noexcept {
auto program = mEngine.getDriverApi().createProgram(std::move(p));
assert(program);
@@ -463,7 +493,7 @@ void FMaterial::applyPendingEdits() noexcept {
/**
* Callback handlers for the debug server, potentially called from any thread. These methods are
* never called during normal operation and exist for debugging purposes only.
*
*
* @{
*/
@@ -474,8 +504,7 @@ void FMaterial::onEditCallback(void* userdata, const utils::CString& name, const
// This is called on a web server thread so we defer clearing the program cache
// and swapping out the MaterialParser until the next getProgram call.
material->mPendingEdits = FMaterial::createParser(engine.getBackend(), packageData,
packageSize);
material->mPendingEdits = createParser(engine.getBackend(), packageData, packageSize);
}
void FMaterial::onQueryCallback(void* userdata, uint64_t* pVariants) {
@@ -492,31 +521,6 @@ void FMaterial::onQueryCallback(void* userdata, uint64_t* pVariants) {
/** @}*/
MaterialParser* FMaterial::createParser(backend::Backend backend, const void* data, size_t size) {
MaterialParser* materialParser = new MaterialParser(backend, data, size);
MaterialParser::ParseResult materialResult = materialParser->parse();
if (!ASSERT_POSTCONDITION_NON_FATAL(materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND,
"the material was not built for the %s backend\n", backendToString(backend))) {
return nullptr;
}
if (!ASSERT_POSTCONDITION_NON_FATAL(materialResult == MaterialParser::ParseResult::SUCCESS,
"could not parse the material package")) {
return nullptr;
}
uint32_t version = 0;
materialParser->getMaterialVersion(&version);
ASSERT_PRECONDITION(version == MATERIAL_VERSION, "Material version mismatch. Expected %d but "
"received %d.", MATERIAL_VERSION, version);
assert(backend != Backend::DEFAULT && "Default backend has not been resolved.");
return materialParser;
}
void FMaterial::destroyPrograms(FEngine& engine) {
DriverApi& driverApi = engine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;

View File

@@ -228,6 +228,12 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
return;
}
FRenderTarget* currentRenderTarget = upcast(view.getRenderTarget());
if (mPreviousRenderTarget != currentRenderTarget) {
initializeClearFlags();
mPreviousRenderTarget = currentRenderTarget;
}
view.prepare(engine, driver, arena, svp, getShaderUserTime());
// start froxelization immediately, it has no dependencies
@@ -899,14 +905,8 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
float l = float(time.count() - h);
mShaderUserTime = { h, l, 0, 0 };
// We always discard and clear the depth+stencil buffers -- we don't allow sharing these
// across views (clear implies discard)
mDiscardedFlags = ((mClearOptions.discard || mClearOptions.clear) ?
TargetBufferFlags::COLOR : TargetBufferFlags::NONE)
| TargetBufferFlags::DEPTH_AND_STENCIL;
mClearFlags = (mClearOptions.clear ? TargetBufferFlags::COLOR : TargetBufferFlags::NONE)
| TargetBufferFlags::DEPTH_AND_STENCIL;
initializeClearFlags();
mPreviousRenderTarget = nullptr;
mBeginFrameInternal = {};
@@ -1099,6 +1099,17 @@ Handle<HwRenderTarget> FRenderer::getRenderTarget(FView& view) const noexcept {
return viewRenderTarget ? viewRenderTarget : mRenderTarget;
}
void FRenderer::initializeClearFlags() {
// We always discard and clear the depth+stencil buffers -- we don't allow sharing these
// across views (clear implies discard)
mDiscardedFlags = ((mClearOptions.discard || mClearOptions.clear) ?
TargetBufferFlags::COLOR : TargetBufferFlags::NONE)
| TargetBufferFlags::DEPTH_AND_STENCIL;
mClearFlags = (mClearOptions.clear ? TargetBufferFlags::COLOR : TargetBufferFlags::NONE)
| TargetBufferFlags::DEPTH_AND_STENCIL;
}
// ------------------------------------------------------------------------------------------------
// Trampoline calling into private implementation
// ------------------------------------------------------------------------------------------------

View File

@@ -153,8 +153,6 @@ public:
/** @}*/
static MaterialParser* createParser(backend::Backend backend, const void* data, size_t size);
private:
backend::Handle<backend::HwProgram> getProgramSlow(uint8_t variantKey) const noexcept;
backend::Handle<backend::HwProgram> getSurfaceProgramSlow(uint8_t variantKey) const noexcept;

View File

@@ -49,6 +49,7 @@ class Driver;
class View;
class FEngine;
class FRenderTarget;
class FView;
class ShadowMap;
@@ -161,6 +162,8 @@ private:
backend::TextureFormat getHdrFormat(const View& view, bool translucent) const noexcept;
backend::TextureFormat getLdrFormat(bool translucent) const noexcept;
void initializeClearFlags();
using clock = std::chrono::steady_clock;
using Epoch = clock::time_point;
using duration = clock::duration;
@@ -189,6 +192,7 @@ private:
ClearOptions mClearOptions;
backend::TargetBufferFlags mDiscardedFlags{};
backend::TargetBufferFlags mClearFlags{};
FRenderTarget* mPreviousRenderTarget = nullptr;
std::function<void()> mBeginFrameInternal;
// per-frame arena for this Renderer

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.9.8"
spec.version = "1.9.9"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.9.8/filament-v1.9.8-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.9.9/filament-v1.9.9-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.9.8",
"version": "1.9.9",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",