Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36c76daf34 |
@@ -7,3 +7,4 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
- vk: fix stage pool gc logic
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.56.4'
|
||||
implementation 'com.google.android.filament:filament-android:1.56.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.56.4'
|
||||
pod 'Filament', '~> 1.56.0'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,16 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.56.4
|
||||
|
||||
|
||||
## v1.56.3
|
||||
|
||||
|
||||
## v1.56.2
|
||||
|
||||
- vk: fix stage pool gc logic
|
||||
|
||||
## v1.56.1
|
||||
|
||||
## v1.56.0
|
||||
|
||||
@@ -38,7 +38,7 @@ Java_com_google_android_filament_EntityManager_nCreateArray(JNIEnv* env, jclass,
|
||||
// (which it is), but still.
|
||||
em->create((size_t) n, reinterpret_cast<Entity *>(entities));
|
||||
|
||||
env->ReleaseIntArrayElements(entities_, entities, 0);
|
||||
env->ReleaseIntArrayElements(entities_, entities, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -167,7 +167,7 @@ Java_com_google_android_filament_IndirectLight_nGetDirectionEstimateStatic(JNIEn
|
||||
jfloat *outDirection = env->GetFloatArrayElements(outDirection_, NULL);
|
||||
*reinterpret_cast<filament::math::float3*>(outDirection) = IndirectLight::getDirectionEstimate((filament::math::float3*)sh);
|
||||
env->ReleaseFloatArrayElements(outDirection_, outDirection, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -178,5 +178,5 @@ Java_com_google_android_filament_IndirectLight_nGetColorEstimateStatic(JNIEnv *e
|
||||
*reinterpret_cast<filament::math::float4*>(outColor) =
|
||||
IndirectLight::getColorEstimate((filament::math::float3*)sh, math::float3{x, y, z});
|
||||
env->ReleaseFloatArrayElements(outColor_, outColor, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, JNI_ABORT);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.56.4
|
||||
VERSION_NAME=1.56.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+2
-11
@@ -1787,12 +1787,7 @@ non-shader data.
|
||||
declare a variable called <code>eyeDirection</code> you can access it in the fragment shader using
|
||||
<code>variable_eyeDirection</code>. In the vertex shader, the interpolant name is simply a member of
|
||||
the <code>MaterialVertexInputs</code> structure (<code>material.eyeDirection</code> in your example). Each
|
||||
interpolant is of type <code>float4</code> (<code>vec4</code>) in the shaders. By default the precision of the
|
||||
interpolant is <code>highp</code> in <em class="asterisk">both</em> the vertex and fragment shaders.
|
||||
An alternate syntax can be used to specify both the name and precision of the interpolant.
|
||||
In this case the specified precision is used as-is in both fragment and vertex stages, in
|
||||
particular if <code>default</code> is specified the default precision is used is the fragment shader
|
||||
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
|
||||
interpolant is of type <code>float4</code> (<code>vec4</code>) in the shaders.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> name : Skybox,</span>
|
||||
@@ -1803,11 +1798,7 @@ non-shader data.
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> ],</span>
|
||||
<span class="line"> variables : [</span>
|
||||
<span class="line"> eyeDirection,</span>
|
||||
<span class="line"> {</span>
|
||||
<span class="line"> name : eyeColor,</span>
|
||||
<span class="line"> precision : medium</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> eyeDirection</span>
|
||||
<span class="line"> ],</span>
|
||||
<span class="line"> vertexDomain : device,</span>
|
||||
<span class="line"> depthWrite : <span class="hljs-literal">false</span>,</span>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -135,7 +135,6 @@ struct MetalContext {
|
||||
bool supportsTextureSwizzling = false;
|
||||
bool supportsAutoDepthResolve = false;
|
||||
bool supportsMemorylessRenderTargets = false;
|
||||
bool supportsDepthClamp = false;
|
||||
uint8_t maxColorRenderTargets = 4;
|
||||
struct {
|
||||
uint8_t common;
|
||||
|
||||
@@ -151,11 +151,6 @@ MetalDriver::MetalDriver(
|
||||
mContext->highestSupportedGpuFamily.mac >= 2; // newer macOS GPUs
|
||||
}
|
||||
|
||||
mContext->supportsDepthClamp = false;
|
||||
if (@available(macOS 10.11, iOS 11.0, *)) {
|
||||
mContext->supportsDepthClamp = true;
|
||||
}
|
||||
|
||||
// In order to support resolve store action on depth attachment, the GPU needs to support it.
|
||||
// Note that support for depth resolve implies support for stencil resolve using .sample0 resolve filter.
|
||||
// (Other resolve filters are supported starting .apple5 and .mac2 families).
|
||||
@@ -1068,7 +1063,7 @@ bool MetalDriver::isProtectedTexturesSupported() {
|
||||
}
|
||||
|
||||
bool MetalDriver::isDepthClampSupported() {
|
||||
return mContext->supportsDepthClamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
@@ -1263,7 +1258,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->cullModeState.invalidate();
|
||||
mContext->windingState.invalidate();
|
||||
mContext->scissorRectState.invalidate();
|
||||
mContext->depthClampState.invalidate();
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedDescriptorSets.clear();
|
||||
@@ -1735,12 +1729,10 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
}
|
||||
|
||||
// depth clip mode
|
||||
if (mContext->supportsDepthClamp) {
|
||||
MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
|
||||
mContext->depthClampState.updateState(depthClipMode);
|
||||
if (mContext->depthClampState.stateChanged()) {
|
||||
[mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode];
|
||||
}
|
||||
MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
|
||||
mContext->depthClampState.updateState(depthClipMode);
|
||||
if (mContext->depthClampState.stateChanged()) {
|
||||
[mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode];
|
||||
}
|
||||
|
||||
// Set the depth-stencil state, if a state change is needed.
|
||||
|
||||
@@ -226,11 +226,9 @@ MetalShaderCompiler::program_token_t MetalShaderCompiler::createProgram(
|
||||
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
|
||||
mCompilerThreadPool.queue(priorityQueue, token,
|
||||
[this, name, device = mDevice, program = std::move(program), token]() {
|
||||
@autoreleasepool {
|
||||
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||
token->set(compiledProgram);
|
||||
mCallbackManager.put(token->handle);
|
||||
}
|
||||
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||
token->set(compiledProgram);
|
||||
mCallbackManager.put(token->handle);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
@@ -500,13 +500,11 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
// qualcomm seems to have no problem with this (which is good for us)
|
||||
bugs->allow_read_only_ancillary_feedback_loop = true;
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// Older Adreno devices that support ES3.0 only tend to be extremely buggy, so we
|
||||
// fall back to ES2.0.
|
||||
if (major == 3 && minor == 0) {
|
||||
bugs->force_feature_level0 = true;
|
||||
}
|
||||
#endif
|
||||
} else if (strstr(renderer, "Mali")) {
|
||||
// ARM GPU
|
||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||
|
||||
@@ -64,14 +64,10 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mLib) {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(mLib)
|
||||
<< "Unable to dlopen libOSMesa to create a software GL context";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(OSMesaGetProcAddress)
|
||||
<< "Unable to against libOSMesa to create a software GL context";
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
|
||||
OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext");
|
||||
OSMesaDestroyContext =
|
||||
@@ -80,9 +76,7 @@ public:
|
||||
}
|
||||
|
||||
~OSMesaAPI() {
|
||||
if (mLib) {
|
||||
dlclose(mLib);
|
||||
}
|
||||
dlclose(mLib);
|
||||
}
|
||||
private:
|
||||
void* mLib = nullptr;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace filament {
|
||||
* filament::Camera* myCamera = engine->createCamera(myCameraEntity);
|
||||
* myCamera->setProjection(45, 16.0/9.0, 0.1, 1.0);
|
||||
* myCamera->lookAt({0, 1.60, 1}, {0, 0, 0});
|
||||
* engine->destroyCameraComponent(myCameraEntity);
|
||||
* engine->destroyCameraComponent(myCamera);
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
*
|
||||
|
||||
+15
-38
@@ -864,44 +864,21 @@ backend::Viewport RenderPass::Executor::applyScissorViewport(
|
||||
backend::Viewport const& scissorViewport, backend::Viewport const& scissor) noexcept {
|
||||
// scissor is set, we need to apply the offset/clip
|
||||
// clang vectorizes this!
|
||||
constexpr int64_t maxvali = std::numeric_limits<int32_t>::max();
|
||||
|
||||
// we do all the offsetting/clipping math in 64 bits below to avoid overflows
|
||||
struct {
|
||||
int64_t l;
|
||||
int64_t b;
|
||||
int64_t r;
|
||||
int64_t t;
|
||||
} svp, s;
|
||||
|
||||
// convert scissorViewport to {left,bottom,right,top} format
|
||||
svp.l = scissorViewport.left;
|
||||
svp.b = scissorViewport.bottom;
|
||||
svp.r = svp.l + scissorViewport.width;
|
||||
svp.t = svp.b + scissorViewport.height;
|
||||
|
||||
// convert scissor to {left,bottom,right,top} format and offset by scissorViewport's left,bottom
|
||||
s.l = svp.l + scissor.left;
|
||||
s.b = svp.b + scissor.bottom;
|
||||
s.r = s.l + scissor.width;
|
||||
s.t = s.b + scissor.height;
|
||||
|
||||
// clip to the scissorViewport
|
||||
s.l = std::max(s.l, svp.l);
|
||||
s.b = std::max(s.b, svp.b);
|
||||
s.r = std::min(s.r, svp.r);
|
||||
s.t = std::min(s.t, svp.t);
|
||||
|
||||
// clip to positive int32_t
|
||||
s.l = std::max(s.l, int64_t(0));
|
||||
s.b = std::max(s.b, int64_t(0));
|
||||
s.r = std::min(s.r, maxvali);
|
||||
s.t = std::min(s.t, maxvali);
|
||||
|
||||
assert_invariant(s.r >= s.l && s.t >= s.b);
|
||||
|
||||
// convert back to Viewport format
|
||||
return { int32_t(s.l), int32_t(s.b), uint32_t(s.r - s.l), uint32_t(s.t - s.b) };
|
||||
constexpr int32_t maxvali = std::numeric_limits<int32_t>::max();
|
||||
// compute new left/bottom, assume no overflow
|
||||
int32_t const l = scissor.left + scissorViewport.left;
|
||||
int32_t const b = scissor.bottom + scissorViewport.bottom;
|
||||
// compute right/top without overflowing, scissor.width/height guaranteed
|
||||
// to convert to int32
|
||||
int32_t r = (l > maxvali - int32_t(scissor.width)) ? maxvali : l + int32_t(scissor.width);
|
||||
int32_t t = (b > maxvali - int32_t(scissor.height)) ? maxvali : b + int32_t(scissor.height);
|
||||
// clip to the viewport
|
||||
assert_invariant(l == std::max(l, scissorViewport.left));
|
||||
assert_invariant(b == std::max(b, scissorViewport.bottom));
|
||||
r = std::min(r, scissorViewport.left + int32_t(scissorViewport.width));
|
||||
t = std::min(t, scissorViewport.bottom + int32_t(scissorViewport.height));
|
||||
assert_invariant(r >= l && t >= b);
|
||||
return { l, b, uint32_t(r - l), uint32_t(t - b) };
|
||||
}
|
||||
|
||||
UTILS_NOINLINE // no need to be inlined
|
||||
|
||||
@@ -529,31 +529,19 @@ void FEngine::shutdown() {
|
||||
mPerViewDescriptorSetLayoutSsrVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
mPerRenderableDescriptorSetLayout.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
|
||||
driver.destroyRenderPrimitive(std::move(mFullScreenTriangleRph));
|
||||
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
|
||||
|
||||
destroy(mFullScreenTriangleIb);
|
||||
mFullScreenTriangleIb = nullptr;
|
||||
|
||||
destroy(mFullScreenTriangleVb);
|
||||
mFullScreenTriangleVb = nullptr;
|
||||
|
||||
destroy(mDummyMorphTargetBuffer);
|
||||
mDummyMorphTargetBuffer = nullptr;
|
||||
|
||||
destroy(mDefaultIblTexture);
|
||||
mDefaultIblTexture = nullptr;
|
||||
|
||||
destroy(mDefaultIbl);
|
||||
mDefaultIbl = nullptr;
|
||||
|
||||
destroy(mDefaultColorGrading);
|
||||
mDefaultColorGrading = nullptr;
|
||||
|
||||
destroy(mDefaultMaterial);
|
||||
mDefaultMaterial = nullptr;
|
||||
|
||||
destroy(mUnprotectedDummySwapchain);
|
||||
mUnprotectedDummySwapchain = nullptr;
|
||||
|
||||
/*
|
||||
* clean-up after the user -- we call terminate on each "leaked" object and clear each list.
|
||||
@@ -570,7 +558,6 @@ void FEngine::shutdown() {
|
||||
|
||||
// this must be done after Skyboxes and before materials
|
||||
destroy(mSkyboxMaterial);
|
||||
mSkyboxMaterial = nullptr;
|
||||
|
||||
cleanupResourceList(std::move(mBufferObjects));
|
||||
cleanupResourceList(std::move(mIndexBuffers));
|
||||
@@ -587,12 +574,12 @@ void FEngine::shutdown() {
|
||||
|
||||
cleanupResourceListLocked(mFenceListLock, std::move(mFences));
|
||||
|
||||
driver.destroyTexture(std::move(mDummyOneTexture));
|
||||
driver.destroyTexture(std::move(mDummyOneTextureArray));
|
||||
driver.destroyTexture(std::move(mDummyZeroTexture));
|
||||
driver.destroyTexture(std::move(mDummyZeroTextureArray));
|
||||
driver.destroyTexture(mDummyOneTexture);
|
||||
driver.destroyTexture(mDummyOneTextureArray);
|
||||
driver.destroyTexture(mDummyZeroTexture);
|
||||
driver.destroyTexture(mDummyZeroTextureArray);
|
||||
|
||||
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
|
||||
driver.destroyRenderTarget(mDefaultRenderTarget);
|
||||
|
||||
/*
|
||||
* Shutdown the backend...
|
||||
@@ -1159,13 +1146,8 @@ bool FEngine::destroy(const FMaterial* ptr) {
|
||||
if (!ASSERT_PRECONDITION_NON_FATAL(pos->second.empty(),
|
||||
"destroying material \"%s\" but %u instances still alive",
|
||||
ptr->getName().c_str(), (*pos).second.size())) {
|
||||
// We return true here, because the material has been destroyed. However, this
|
||||
// leaks this material's ResourceList<FMaterialInstance> until the engine
|
||||
// is shut down. Note that it's still possible for the MaterialInstances to be
|
||||
// destroyed manually.
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
mMaterialInstances.erase(pos);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -321,7 +321,11 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
parser->getSpecularAntiAliasingThreshold(&mSpecularAntiAliasingThreshold);
|
||||
}
|
||||
|
||||
parser->hasCustomDepthShader(&mHasCustomDepthShader);
|
||||
processBlendingMode(parser);
|
||||
processSpecializationConstants(engine, builder, parser);
|
||||
processPushConstants(engine, parser);
|
||||
processDepthVariants(engine, parser);
|
||||
processDescriptorSets(engine, parser);
|
||||
|
||||
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
|
||||
mIsVariantLit,
|
||||
@@ -329,12 +333,6 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
mRefractionMode == RefractionMode::SCREEN_SPACE,
|
||||
!(mVariantFilterMask & +UserVariantFilterBit::FOG));
|
||||
|
||||
processBlendingMode(parser);
|
||||
processSpecializationConstants(engine, builder, parser);
|
||||
processPushConstants(engine, parser);
|
||||
processDescriptorSets(engine, parser);
|
||||
precacheDepthVariants(engine);
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Register the material with matdbg.
|
||||
matdbg::DebugServer* server = downcast(engine).debug.server;
|
||||
@@ -348,21 +346,53 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
FMaterial::~FMaterial() noexcept = default;
|
||||
|
||||
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
|
||||
// Note: This API is not public at the moment, so it's okay to have some debugging logs
|
||||
// and extra checks.
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mHasCustomDepthShader) {
|
||||
// it would be unsafe to invalidate any of the cached depth variant
|
||||
if (UTILS_UNLIKELY(!((variantMask & Variant::DEP) && !(variantValue & Variant::DEP)))) {
|
||||
slog.w << io::hex << "FMaterial::invalidate("
|
||||
<< +variantMask << ", " << +variantValue
|
||||
<< ") would corrupt the depth variant cache" << io::endl;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
|
||||
auto hasDefaultDepthVariant = [pDefaultMaterial](Variant k) {
|
||||
auto const& end = pDefaultMaterial->mDepthVariants.end();
|
||||
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
|
||||
};
|
||||
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE) {
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
Variant const variant(k);
|
||||
if ((k & variantMask) == variantValue) {
|
||||
if (UTILS_LIKELY(!mIsDefaultMaterial)) {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free it now.
|
||||
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
|
||||
!mHasCustomDepthShader &&
|
||||
hasDefaultDepthVariant(variant);
|
||||
if (isSharedVariant) {
|
||||
// we don't own this variant, skip.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
variantMask |= Variant::DEP;
|
||||
variantValue &= ~Variant::DEP;
|
||||
|
||||
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
|
||||
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
|
||||
pDefaultMaterial->prepareProgram(variant);
|
||||
if (!cachedPrograms[variant.key]) {
|
||||
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mMaterialDomain == MaterialDomain::POST_PROCESS) {
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
} else if (mMaterialDomain == MaterialDomain::COMPUTE) {
|
||||
// TODO: handle compute variants if any
|
||||
}
|
||||
destroyPrograms(mEngine, variantMask, variantValue);
|
||||
}
|
||||
|
||||
void FMaterial::terminate(FEngine& engine) {
|
||||
@@ -602,42 +632,11 @@ Program FMaterial::getProgramWithVariants(
|
||||
}
|
||||
|
||||
void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept {
|
||||
FEngine const& engine = mEngine;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
|
||||
bool const isSharedVariant =
|
||||
(mMaterialDomain == MaterialDomain::SURFACE) &&
|
||||
!mIsDefaultMaterial && !mHasCustomDepthShader &&
|
||||
Variant::isValidDepthVariant(variant);
|
||||
|
||||
// Check if the default material has this program cached
|
||||
if (isSharedVariant) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial) {
|
||||
auto program = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (program) {
|
||||
mCachedPrograms[variant.key] = program;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto program = driverApi.createProgram(std::move(p));
|
||||
driverApi.setDebugTag(program.getId(), mName);
|
||||
assert_invariant(!mCachedPrograms[variant.key]);
|
||||
auto program = mEngine.getDriverApi().createProgram(std::move(p));
|
||||
mEngine.getDriverApi().setDebugTag(program.getId(), mName);
|
||||
assert_invariant(program);
|
||||
mCachedPrograms[variant.key] = program;
|
||||
|
||||
// If the default material doesn't already have this program cached, and all caching conditions
|
||||
// are met (Surface Domain and no custom depth shader), cache it now.
|
||||
// New Materials will inherit these program automatically.
|
||||
if (isSharedVariant) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
// set the tag to the default material name
|
||||
driverApi.setDebugTag(program.getId(), mName);
|
||||
pDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const noexcept {
|
||||
@@ -742,76 +741,29 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pVariants) {
|
||||
#endif // FILAMENT_ENABLE_MATDBG
|
||||
|
||||
|
||||
void FMaterial::destroyPrograms(FEngine& engine,
|
||||
Variant::type_t const variantMask, Variant::type_t const variantValue) {
|
||||
|
||||
void FMaterial::destroyPrograms(FEngine& engine) {
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
|
||||
switch (mMaterialDomain) {
|
||||
case MaterialDomain::SURFACE: {
|
||||
if (mIsDefaultMaterial || mHasCustomDepthShader) {
|
||||
// default material or we have custom depth shaders, we destroy all variants
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variants, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free them now.
|
||||
auto hasDefaultDepthVariant = [pDefaultMaterial = engine.getDefaultMaterial()](Variant k) {
|
||||
auto const& end = pDefaultMaterial->mDepthVariants.end();
|
||||
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
|
||||
};
|
||||
|
||||
// During Engine::shutdown(), auto-cleanup destroys the default material first,
|
||||
// so this can be null, but this is only used for debugging.
|
||||
UTILS_UNUSED_IN_RELEASE
|
||||
auto UTILS_NULLABLE pDefaultMaterial = engine.getDefaultMaterial();
|
||||
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variant, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
if (Variant::isValidDepthVariant(Variant(k))) {
|
||||
// By construction this should always be true, because this
|
||||
// field is populated only when a material creates the program
|
||||
// for this variant.
|
||||
// During Engine::shutdown, auto-cleanup destroys the
|
||||
// default material first
|
||||
assert_invariant(!pDefaultMaterial ||
|
||||
pDefaultMaterial->mCachedPrograms[k]);
|
||||
// we don't own this variant, skip, but clear the entry.
|
||||
cachedPrograms[k].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
const Variant variant(k);
|
||||
if (!mIsDefaultMaterial) {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free it now.
|
||||
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
|
||||
!mHasCustomDepthShader && hasDefaultDepthVariant(variant);
|
||||
if (isSharedVariant) {
|
||||
// we don't own this variant, skip.
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MaterialDomain::POST_PROCESS: {
|
||||
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variant, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MaterialDomain::COMPUTE: {
|
||||
// Compute programs don't have variants
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[0]));
|
||||
break;
|
||||
}
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1076,32 +1028,34 @@ void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* pars
|
||||
});
|
||||
}
|
||||
|
||||
void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
// pre-cache all depth variants inside the default material. Note that this should be
|
||||
// entirely optional; if we remove this pre-caching, these variants will be populated
|
||||
// later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more
|
||||
// memory and increases init time, but reduces hiccups during the first frame.
|
||||
void FMaterial::processDepthVariants(FEngine& engine, MaterialParser const* const parser) {
|
||||
parser->hasCustomDepthShader(&mHasCustomDepthShader);
|
||||
|
||||
if (UTILS_UNLIKELY(mIsDefaultMaterial)) {
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(variant);
|
||||
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
|
||||
filaflat::MaterialChunk const& materialChunk{ parser->getMaterialChunk() };
|
||||
auto variants = FixedCapacityVector<Variant>::with_capacity(materialChunk.getShaderCount());
|
||||
materialChunk.visitShaders([&variants](
|
||||
ShaderModel, Variant variant, ShaderStage) {
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
variants.push_back(variant);
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
std::sort(variants.begin(), variants.end(),
|
||||
[](Variant lhs, Variant rhs) { return lhs.key < rhs.key; });
|
||||
auto pos = std::unique(variants.begin(), variants.end());
|
||||
variants.resize(std::distance(variants.begin(), pos));
|
||||
std::swap(mDepthVariants, variants);
|
||||
}
|
||||
|
||||
// if possible pre-cache all depth variants from the default material
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mHasCustomDepthShader) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
assert_invariant(pDefaultMaterial);
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE) {
|
||||
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
|
||||
pDefaultMaterial->prepareProgram(variant);
|
||||
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,9 +218,7 @@ public:
|
||||
|
||||
uint32_t generateMaterialInstanceId() const noexcept { return mMaterialInstanceId++; }
|
||||
|
||||
void destroyPrograms(FEngine& engine,
|
||||
Variant::type_t variantMask = 0,
|
||||
Variant::type_t variantValue = 0);
|
||||
void destroyPrograms(FEngine& engine);
|
||||
|
||||
// return the id of a specialization constant specified by name for this material
|
||||
std::optional<uint32_t> getSpecializationConstantId(std::string_view name) const noexcept ;
|
||||
@@ -284,7 +282,7 @@ private:
|
||||
|
||||
void processPushConstants(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
void precacheDepthVariants(FEngine& engine);
|
||||
void processDepthVariants(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
@@ -333,6 +331,7 @@ private:
|
||||
SamplerInterfaceBlock mSamplerInterfaceBlock;
|
||||
BufferInterfaceBlock mUniformInterfaceBlock;
|
||||
SubpassInfo mSubpassInfo;
|
||||
utils::FixedCapacityVector<Variant> mDepthVariants; // only populated with default material
|
||||
|
||||
using BindingUniformInfoContainer = utils::FixedCapacityVector<std::tuple<
|
||||
uint8_t, utils::CString, backend::Program::UniformInfo>>;
|
||||
|
||||
@@ -963,11 +963,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
uint32_t(float(xvp.width ) * aoOptions.resolution),
|
||||
uint32_t(float(xvp.height) * aoOptions.resolution)});
|
||||
|
||||
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
|
||||
// this descriptor-set is also used for ssr/picking/structure and these could be stale
|
||||
// it would be better to use a separate desriptor-set for those two cases so that we don't
|
||||
// have to do this
|
||||
view.unbindSamplers(driver);
|
||||
view.commitUniformsAndSamplers(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -912,10 +912,6 @@ void FView::commitUniformsAndSamplers(DriverApi& driver) const noexcept {
|
||||
mColorPassDescriptorSet.commit(driver);
|
||||
}
|
||||
|
||||
void FView::unbindSamplers(DriverApi& driver) noexcept {
|
||||
mColorPassDescriptorSet.unbindSamplers(driver);
|
||||
}
|
||||
|
||||
void FView::commitFroxels(DriverApi& driverApi) const noexcept {
|
||||
if (mHasDynamicLighting) {
|
||||
mFroxelizer.commit(driverApi);
|
||||
|
||||
@@ -174,7 +174,6 @@ public:
|
||||
|
||||
void commitFroxels(backend::DriverApi& driverApi) const noexcept;
|
||||
void commitUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
void unbindSamplers(backend::DriverApi& driver) noexcept;
|
||||
|
||||
utils::JobSystem::Job* getFroxelizerSync() const noexcept { return mFroxelizerSync; }
|
||||
void setFroxelizerSync(utils::JobSystem::Job* sync) noexcept { mFroxelizerSync = sync; }
|
||||
@@ -535,7 +534,7 @@ private:
|
||||
Viewport mViewport;
|
||||
bool mCulling = true;
|
||||
bool mFrontFaceWindingInverted = false;
|
||||
bool mIsTransparentPickingEnabled = false;
|
||||
bool mIsTransparentPickingEnabled = true;
|
||||
|
||||
FRenderTarget* mRenderTarget = nullptr;
|
||||
|
||||
|
||||
@@ -541,17 +541,6 @@ void ColorPassDescriptorSet::commit(backend::DriverApi& driver) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::unbindSamplers(DriverApi&) noexcept {
|
||||
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
|
||||
// this descriptor-set is also used for ssr/picking/structure and these could be stale
|
||||
// it would be better to use a separate descriptor-set for those two cases so that we don't
|
||||
// have to do this
|
||||
setSampler(+PerViewBindingPoints::STRUCTURE, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SSAO, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SSR, {}, {});
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::setSampler(backend::descriptor_binding_t binding,
|
||||
TextureHandle th, SamplerParams params) noexcept {
|
||||
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
|
||||
|
||||
@@ -158,8 +158,6 @@ public:
|
||||
// update local data into GPU UBO
|
||||
void commit(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void unbindSamplers(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// bind this UBO
|
||||
void bind(backend::DriverApi& driver, uint8_t index) const noexcept {
|
||||
mDescriptorSet[index].bind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.56.4"
|
||||
spec.version = "1.56.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.4/filament-v1.56.4-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.0/filament-v1.56.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -38,13 +38,12 @@ bool initBinder() {
|
||||
}
|
||||
}
|
||||
if (!g_driver.library) {
|
||||
// The library has been linked explicitly during compile.
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
g_driver.OSMesaGetProcAddress =
|
||||
(ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc)
|
||||
dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
|
||||
return g_driver.OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
@@ -53,9 +52,7 @@ void* loadFunction(const char* name) {
|
||||
}
|
||||
|
||||
void shutdownBinder() {
|
||||
if (g_driver.library) {
|
||||
dlclose(g_driver.library);
|
||||
}
|
||||
dlclose(g_driver.library);
|
||||
memset(&g_driver, 0, sizeof(g_driver));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 56;
|
||||
static constexpr size_t MATERIAL_VERSION = 55;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
@@ -272,8 +271,6 @@ namespace VariantUtils {
|
||||
utils::Slice<Variant> getLitVariants() noexcept UTILS_PURE;
|
||||
// list of unlit variants
|
||||
utils::Slice<Variant> getUnlitVariants() noexcept UTILS_PURE;
|
||||
// list of depth variants
|
||||
utils::Slice<Variant> getDepthVariants() noexcept UTILS_PURE;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -16,15 +16,8 @@
|
||||
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <utils/Slice.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
Variant Variant::filterUserVariant(
|
||||
@@ -72,8 +65,6 @@ Variant Variant::filterUserVariant(
|
||||
|
||||
namespace details {
|
||||
|
||||
namespace {
|
||||
|
||||
// Compile-time variant count for lit and unlit
|
||||
constexpr inline size_t variant_count(bool lit) noexcept {
|
||||
size_t count = 0;
|
||||
@@ -90,17 +81,6 @@ constexpr inline size_t variant_count(bool lit) noexcept {
|
||||
return count;
|
||||
}
|
||||
|
||||
constexpr inline size_t depth_variant_count() noexcept {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < VARIANT_COUNT; i++) {
|
||||
Variant const variant(i);
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Compile-time variant list for lit and unlit
|
||||
template<bool LIT>
|
||||
constexpr auto get_variants() noexcept {
|
||||
@@ -118,18 +98,9 @@ constexpr auto get_variants() noexcept {
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
static auto const gLitVariants{ details::get_variants<true>() };
|
||||
static auto const gUnlitVariants{ details::get_variants<false>() };
|
||||
|
||||
constexpr auto get_depth_variants() noexcept {
|
||||
std::array<Variant, depth_variant_count()> variants;
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < VARIANT_COUNT; i++) {
|
||||
Variant const variant(i);
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
variants[count++] = variant;
|
||||
}
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
// Below are compile time sanity-check tests
|
||||
constexpr inline bool reserved_is_not_valid() noexcept {
|
||||
@@ -192,13 +163,6 @@ constexpr inline size_t fragment_variant_count() noexcept {
|
||||
return count;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
static auto const gLitVariants{ details::get_variants<true>() };
|
||||
static auto const gUnlitVariants{ details::get_variants<false>() };
|
||||
static auto const gDepthVariants{ details::get_depth_variants() };
|
||||
|
||||
static_assert(reserved_is_not_valid());
|
||||
static_assert(reserved_variant_count() == 160);
|
||||
static_assert(valid_variant_count() == 96);
|
||||
@@ -218,10 +182,6 @@ utils::Slice<Variant> getUnlitVariants() noexcept {
|
||||
return { details::gUnlitVariants.data(), details::gUnlitVariants.size() };
|
||||
}
|
||||
|
||||
utils::Slice<Variant> getDepthVariants() noexcept {
|
||||
return { details::gDepthVariants.data(), details::gDepthVariants.size() };
|
||||
}
|
||||
|
||||
}; // VariantUtils
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -264,7 +264,7 @@ size_t Animator::getAnimationCount() const {
|
||||
|
||||
void Animator::applyAnimation(size_t animationIndex, float time) const {
|
||||
const Animation& anim = mImpl->animations[animationIndex];
|
||||
time = time == anim.duration ? time : fmod(time, anim.duration);
|
||||
time = fmod(time, anim.duration);
|
||||
TransformManager& transformManager = *mImpl->transformManager;
|
||||
transformManager.openLocalTransformTransaction();
|
||||
for (const auto& channel : anim.channels) {
|
||||
|
||||
@@ -1043,8 +1043,6 @@ int main(int argc, char** argv) {
|
||||
delete app.resourceLoader;
|
||||
delete app.stbDecoder;
|
||||
delete app.ktxDecoder;
|
||||
delete app.automationSpec;
|
||||
delete app.automationEngine;
|
||||
|
||||
AssetLoader::destroy(&app.assetLoader);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.56.4",
|
||||
"version": "1.56.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user