Compare commits

..
Author SHA1 Message Date
Powei Feng 36c76daf34 material: fix depth variant leak
The default material does not cover all of the depth variants,
and so for the client material's depth variants (with no custom
depth shader), we need to check if the program is allocated for
the material or if it is actually part of the default material.
2024-11-14 15:13:48 -08:00
73 changed files with 230 additions and 868 deletions
+1
View File
@@ -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
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.56.5'
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.5'
pod 'Filament', '~> 1.56.0'
```
## Documentation
-13
View File
@@ -7,19 +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.5
## 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);
}
@@ -25,14 +25,13 @@ using namespace filament;
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount, jint shadowQuality) {
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, buffer_, size);
auto builder = Material::Builder();
if (shBandCount) {
builder.sphericalHarmonicsBandCount(shBandCount);
}
builder.shadowSamplingQuality((Material::Builder::ShadowSamplingQuality)shadowQuality);
Material* material = builder
.package(buffer.getData(), buffer.getSize())
.build(*engine);
@@ -344,18 +344,9 @@ public class Material {
}
public static class Builder {
public enum ShadowSamplingQuality {
/** 2x2 PCF */
HARD,
/** 3x3 gaussian filter */
LOW,
}
private Buffer mBuffer;
private int mSize;
private int mShBandCount = 0;
private ShadowSamplingQuality mShadowSamplingQuality = ShadowSamplingQuality.LOW;
/**
* Specifies the material data. The material data is a binary blob produced by
@@ -387,18 +378,6 @@ public class Material {
return this;
}
/**
* Set the quality of shadow sampling. This is only taken into account
* if this material is lit and in the surface domain.
* @param quality
* @return Reference to this Builder for chaining calls.
*/
@NonNull
public Builder shadowSamplingQuality(ShadowSamplingQuality quality) {
mShadowSamplingQuality = quality;
return this;
}
/**
* Creates and returns the Material object.
*
@@ -411,7 +390,7 @@ public class Material {
@NonNull
public Material build(@NonNull Engine engine) {
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
mBuffer, mSize, mShBandCount, mShadowSamplingQuality.ordinal());
mBuffer, mSize, mShBandCount);
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
return new Material(nativeMaterial);
}
@@ -1062,7 +1041,7 @@ public class Material {
mNativeObject = 0;
}
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount, int shadowQuality);
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
private static native long nCreateInstance(long nativeMaterial);
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
private static native long nGetDefaultInstance(long nativeMaterial);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.56.5
VERSION_NAME=1.56.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -11
View File
@@ -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.
+2 -4
View File
@@ -226,12 +226,10 @@ if (FILAMENT_SUPPORTS_VULKAN)
src/vulkan/VulkanUtility.cpp
src/vulkan/VulkanUtility.h
)
if (LINUX OR WIN32)
list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp)
if (ANDROID OR LINUX OR WIN32)
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroidLinuxWindows.cpp)
elseif (APPLE OR IOS)
list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm)
elseif (ANDROID)
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp)
endif()
endif()
@@ -292,64 +292,8 @@ public:
*/
VkQueue getProtectedGraphicsQueue() const noexcept;
struct ExternalImageMetadata {
/**
* The width of the external image
*/
uint32_t width;
/**
* The height of the external image
*/
uint32_t height;
/**
* The layer count of the external image
*/
uint32_t layers;
/**
* The format of the external image
*/
VkFormat format;
/**
* An external buffer can be protected. This tells you if it is.
*/
bool isProtected;
/**
* The type of external format (opaque int) if used.
*/
uint64_t externalFormat;
/**
* Image usage
*/
VkImageUsageFlags usage;
/**
* Allocation size
*/
VkDeviceSize allocationSize;
/**
* Heap information
*/
uint32_t memoryTypeBits;
};
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
using ImageData = std::pair<VkImage, VkDeviceMemory>;
virtual ImageData createExternalImage(void* externalImage,
const ExternalImageMetadata& metadata);
private:
static ExtensionSet getSwapchainInstanceExtensions();
static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage,
VkDevice device);
static ImageData createExternalImageImpl(void* externalImage, VkDevice device,
const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata);
// Platform dependent helper methods
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
@@ -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;
+5 -13
View File
@@ -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;
+1 -20
View File
@@ -544,25 +544,7 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
}
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) {
FVK_SYSTRACE_SCOPE();
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
if (metadata.isProtected) {
usage |= backend::TextureUsage::PROTECTED;
}
assert_invariant(width == metadata.width);
assert_invariant(height == metadata.height);
assert_invariant(getVkFormat(format) == metadata.format);
const auto& data = mPlatform->createExternalImage(externalImage, metadata);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
1, metadata.width, metadata.height, usage, mStagePool);
texture.inc();
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
}
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
@@ -1190,7 +1172,6 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
}
void VulkanDriver::setExternalImage(Handle<HwTexture> th, void* image) {
}
void VulkanDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
@@ -75,16 +75,15 @@ void VulkanSwapChain::update() {
}
for (auto const color: bundle.colors) {
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, colorUsage,
device, mAllocator, mResourceManager, mCommands, color, bundle.colorFormat, 1,
bundle.extent.width, bundle.extent.height, TextureUsage::COLOR_ATTACHMENT,
mStagePool);
mColors.push_back(colorTexture);
}
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, depthUsage,
mStagePool);
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device, mAllocator,
mResourceManager, mCommands, bundle.depth, bundle.depthFormat, 1, bundle.extent.width,
bundle.extent.height, TextureUsage::DEPTH_ATTACHMENT, mStagePool);
mExtent = bundle.extent;
}
@@ -164,15 +164,14 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
// Constructor for internally passed VkImage
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
uint32_t height, TextureUsage tusage, VulkanStagePool& stagePool)
VkFormat format, uint8_t samples, uint32_t width, uint32_t height, TextureUsage tusage,
VulkanStagePool& stagePool)
: HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED,
tusage),
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D),
1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
mState->mTextureImage = image;
mState->mTextureImageMemory = memory;
mPrimaryViewRange = mState->mFullViewRange;
}
+2 -2
View File
@@ -94,8 +94,8 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
// The texture will never destroy the given VkImage, but it does manages its subresources.
VulkanTexture(VkDevice device, VmaAllocator allocator,
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height,
TextureUsage tusage, VulkanStagePool& stagePool);
VkFormat format, uint8_t samples, uint32_t width, uint32_t height, TextureUsage tusage,
VulkanStagePool& stagePool);
// Constructor for creating a texture view for wrt specific mip range
VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context,
+4 -29
View File
@@ -66,8 +66,7 @@ struct Resource {
: resManager(nullptr),
id(HandleBase::nullid),
mCount(0),
restype(ResourceType::UNDEFINED_TYPE),
mHandleConsideredDestroyed(false) {}
restype(ResourceType::UNDEFINED_TYPE) {}
private:
inline void inc() noexcept {
@@ -81,16 +80,6 @@ private:
}
}
// To be able to detect use-after-free, we need a bit to signify if the handle should be
// consider destroyed (from Filament's perspective).
inline void setHandleConsiderDestroyed() noexcept {
mHandleConsideredDestroyed = true;
}
inline bool isHandleConsideredDestroyed() const {
return mHandleConsideredDestroyed;
}
template <typename T>
inline void init(HandleId id, ResourceManager* resManager) {
this->id = id;
@@ -103,9 +92,7 @@ private:
ResourceManager* resManager; // 8
HandleId id; // 4
uint32_t mCount : 24;
ResourceType restype : 7;
bool mHandleConsideredDestroyed : 1; // restype + mCount + mHandleConsideredDestroyed
// is 4 bytes.
ResourceType restype : 6; // restype + mCount is 4 bytes.
friend class ResourceManager;
@@ -118,8 +105,7 @@ struct ThreadSafeResource {
: resManager(nullptr),
id(HandleBase::nullid),
mCount(0),
restype(ResourceType::UNDEFINED_TYPE),
mHandleConsideredDestroyed(false) {}
restype(ResourceType::UNDEFINED_TYPE) {}
private:
inline void inc() noexcept {
@@ -132,16 +118,6 @@ private:
}
}
// To be able to detect use-after-free, we need a bit to signify if the handle should be
// consider destroyed (from Filament's perspective).
inline void setHandleConsiderDestroyed() noexcept {
mHandleConsideredDestroyed = true;
}
inline bool isHandleConsideredDestroyed() const {
return mHandleConsideredDestroyed;
}
template <typename T>
inline void init(HandleId id, ResourceManager* resManager) {
this->id = id;
@@ -154,8 +130,7 @@ private:
ResourceManager* resManager; // 8
HandleId id; // 4
std::atomic<uint32_t> mCount; // 4
ResourceType restype : 7;
bool mHandleConsideredDestroyed : 1; // restype + mHandleConsideredDestroyed is 1 byte
ResourceType restype; // 1
friend class ResourceManager;
@@ -21,7 +21,6 @@
#include "vulkan/memory/ResourceManager.h"
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utility>
@@ -60,10 +59,6 @@ public:
static enabled_resource_ptr<B> cast(ResourceManager* resManager,
Handle<B> const& handle) noexcept {
D* ptr = resManager->handle_cast<D*, B>(handle);
FILAMENT_CHECK_PRECONDITION(!ptr->isHandleConsideredDestroyed())
<< "Handle id=" << ptr->id << " (" << getTypeStr(ptr->restype)
<< ") is being used after it has been freed";
return {ptr};
}
@@ -161,8 +156,6 @@ private:
// only be used from VulkanDriver.
inline void dec() {
assert_invariant(mRef);
assert_invariant(!mRef->isHandleConsideredDestroyed());
mRef->setHandleConsiderDestroyed();
mRef->dec();
}
@@ -194,15 +194,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
#endif
// We only support external image for Android for now, but nothing bars us from
// supporting other platforms.
#if defined(__ANDROID__)
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
#endif
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
@@ -954,16 +945,6 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
return mImpl->mProtectedGraphicsQueue;
}
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
void* externalImage) {
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage,
const ExternalImageMetadata& metadata) {
return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata);
}
#undef SWAPCHAIN_RET_FUNC
}// namespace filament::backend
@@ -1,240 +0,0 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <backend/platforms/VulkanPlatform.h>
#include "vulkan/VulkanConstants.h"
#include <utils/Panic.h>
#include <bluevk/BlueVK.h>
#include <android/hardware_buffer.h>
#include <android/native_window.h>
using namespace bluevk;
namespace filament::backend {
namespace {
void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
VkImageUsageFlags& usage, bool& isProtected) {
// Refer to "11.2.17. External Memory Handle Types" in the spec, and
// Tables 13/14 for how the following derivation works.
bool isDepthFormat = false;
isProtected = false;
switch (desc.format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
format = VK_FORMAT_R8G8B8A8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
format = VK_FORMAT_R8G8B8A8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
format = VK_FORMAT_R8G8B8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
format = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
format = VK_FORMAT_R16G16B16A16_SFLOAT;
break;
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
break;
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
isDepthFormat = true;
format = VK_FORMAT_D16_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
isDepthFormat = true;
format = VK_FORMAT_X8_D24_UNORM_PACK32;
break;
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
isDepthFormat = true;
format = VK_FORMAT_D24_UNORM_S8_UINT;
break;
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
isDepthFormat = true;
format = VK_FORMAT_D32_SFLOAT;
break;
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
isDepthFormat = true;
format = VK_FORMAT_D32_SFLOAT_S8_UINT;
break;
case AHARDWAREBUFFER_FORMAT_S8_UINT:
isDepthFormat = true;
format = VK_FORMAT_S8_UINT;
break;
default:
format = VK_FORMAT_UNDEFINED;
}
// The following only concern usage flags derived from Table 14.
usage = 0;
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
if (isDepthFormat) {
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
} else {
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
}
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
usage = VK_IMAGE_USAGE_STORAGE_BIT;
}
if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
isProtected = true;
}
}
VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
VkDevice device, const VkAllocationCallbacks* allocator,
VulkanPlatform::ExternalImageMetadata const& metadata) {
VulkanPlatform::ImageData data;
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalBuffer);
// if external format we need to specifiy it in the allocation
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
const VkExternalFormatANDROID externalFormat = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
.pNext = nullptr,
.externalFormat = metadata
.externalFormat,// pass down the format (external means we don't have it VK defined)
};
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = useExternalFormat ? &externalFormat : nullptr,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
};
VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
imageInfo.pNext = &externalCreateInfo;
imageInfo.format = metadata.format;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent = {
metadata.width,
metadata.height,
1u,
};
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = metadata.layers;
imageInfo.usage = metadata.usage;
// In the unprotected case add R/W capabilities
if (metadata.isProtected == false)
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VkResult result = vkCreateImage(device, &imageInfo, allocator, &data.first);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateImage failed with error=" << result;
// Allocate the memory
VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo = {
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
.pNext = nullptr,
.buffer = buffer,
};
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.pNext = &androidHardwareBufferInfo,
.image = data.first,
.buffer = VK_NULL_HANDLE,
};
VkMemoryAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &memoryDedicatedAllocateInfo,
.allocationSize = metadata.allocationSize,
.memoryTypeIndex = metadata.memoryTypeBits};
result = vkAllocateMemory(device, &allocInfo, allocator, &data.second);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkAllocateMemory failed with error=" << result;
return data;
}
}// namespace
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
VkDevice device) {
ExternalImageMetadata metadata;
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalImage);
if (__builtin_available(android 26, *)) {
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(buffer, &bufferDesc);
metadata.width = bufferDesc.width;
metadata.height = bufferDesc.height;
metadata.layers = bufferDesc.layers;
getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected);
}
// In the unprotected case add R/W capabilities
if (metadata.isProtected == false) {
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
.pNext = nullptr,
};
VkAndroidHardwareBufferPropertiesANDROID properties = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
.pNext = &formatInfo,
};
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkGetAndroidHardwareBufferProperties failed with error=" << result;
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format);
metadata.externalFormat = formatInfo.externalFormat;
metadata.allocationSize = properties.allocationSize;
metadata.memoryTypeBits = properties.memoryTypeBits;
return metadata;
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
VkDevice device, const VkAllocationCallbacks* allocator,
const ExternalImageMetadata& metadata) {
ImageData data = allocateExternalImage(externalImage, device, allocator, metadata);
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkBindImageMemory error=" << result << ".";
return data;
}
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
return {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
};
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface;
VkExtent2D extent;
VkAndroidSurfaceCreateInfoKHR const createInfo{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.window = (ANativeWindow*) nativeWindow,
};
VkResult const result =
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateAndroidSurfaceKHR with error=" << result;
return {surface, extent};
}
}
@@ -34,7 +34,9 @@
#endif
// Platform specific includes and defines
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined(__ANDROID__)
#include <android/native_window.h>
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
#include <dlfcn.h>
namespace {
typedef struct _wl {
@@ -84,20 +86,11 @@ using namespace bluevk;
namespace filament::backend {
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
void* externalImage, VkDevice device) {
return {};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
VkDevice device, const VkAllocationCallbacks* allocator,
const ExternalImageMetadata& metadata) {
return {};
}
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
VulkanPlatform::ExtensionSet const ret = {
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined(__ANDROID__)
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
#elif defined(LINUX_OR_FREEBSD) && defined(FILAMENT_SUPPORTS_X11)
#if defined(FILAMENT_SUPPORTS_XCB)
@@ -123,7 +116,15 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin
// swap chain extent.
VkExtent2D extent;
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined(__ANDROID__)
VkAndroidSurfaceCreateInfoKHR const createInfo{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.window = (ANativeWindow*) nativeWindow,
};
VkResult const result = vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC,
(VkSurfaceKHR*) &surface);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateAndroidSurfaceKHR error.";
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
wl* ptrval = reinterpret_cast<wl*>(nativeWindow);
extent.width = ptrval->width;
extent.height = ptrval->height;
@@ -63,17 +63,6 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
return ret;
}
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
void* externalImage, VkDevice device) {
return {};
}
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
VkDevice device, const VkAllocationCallbacks* allocator,
const ExternalImageMetadata& metadata) {
return {};
}
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
VkInstance instance, uint64_t flags) noexcept {
VkSurfaceKHR surface;
+1 -1
View File
@@ -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);
* ~~~~~~~~~~~
*
*
-13
View File
@@ -103,11 +103,6 @@ public:
Builder& operator=(Builder const& rhs) noexcept;
Builder& operator=(Builder&& rhs) noexcept;
enum class ShadowSamplingQuality : uint8_t {
HARD, // 2x2 PCF
LOW // 3x3 gaussian filter
};
/**
* Specifies the material data. The material data is a binary blob produced by
* libfilamat or by matc.
@@ -157,14 +152,6 @@ public:
*/
Builder& sphericalHarmonicsBandCount(size_t shBandCount) noexcept;
/**
* Set the quality of shadow sampling. This is only taken into account
* if this material is lit and in the surface domain.
* @param quality
* @return
*/
Builder& shadowSamplingQuality(ShadowSamplingQuality quality) noexcept;
/**
* Creates the Material object and returns a pointer to it.
*
+15 -38
View File
@@ -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
+3 -3
View File
@@ -427,7 +427,7 @@ float FLightManager::getSpotLightInnerCone(Instance i) const noexcept {
void LightManager::ShadowCascades::computeUniformSplits(float splitPositions[3], uint8_t cascades) {
size_t s = 0;
cascades = min(cascades, (uint8_t) 4u);
cascades = max(cascades, (uint8_t) 4u);
for (size_t c = 1; c < cascades; c++) {
splitPositions[s++] = float(c) / float(cascades);
}
@@ -436,7 +436,7 @@ void LightManager::ShadowCascades::computeUniformSplits(float splitPositions[3],
void LightManager::ShadowCascades::computeLogSplits(float splitPositions[3], uint8_t cascades,
float near, float far) {
size_t s = 0;
cascades = min(cascades, (uint8_t) 4u);
cascades = max(cascades, (uint8_t) 4u);
for (size_t c = 1; c < cascades; c++) {
splitPositions[s++] =
(near * std::pow(far / near, float(c) / float(cascades)) - near) / (far - near);
@@ -447,7 +447,7 @@ void LightManager::ShadowCascades::computePracticalSplits(float splitPositions[3
float near, float far, float lambda) {
float uniformSplits[3];
float logSplits[3];
cascades = min(cascades, (uint8_t) 4u);
cascades = max(cascades, (uint8_t) 4u);
computeUniformSplits(uniformSplits, cascades);
computeLogSplits(logSplits, cascades, near, far);
size_t s = 0;
+7 -25
View File
@@ -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;
+97 -153
View File
@@ -123,7 +123,6 @@ struct Material::BuilderDetails {
size_t mSize = 0;
bool mDefaultMaterial = false;
int32_t mShBandsCount = 3;
Builder::ShadowSamplingQuality mShadowSamplingQuality = Builder::ShadowSamplingQuality::LOW;
std::unordered_map<
utils::CString,
std::variant<int32_t, float, bool>,
@@ -153,11 +152,6 @@ Material::Builder& Material::Builder::sphericalHarmonicsBandCount(size_t shBandC
return *this;
}
Material::Builder& Material::Builder::shadowSamplingQuality(ShadowSamplingQuality quality) noexcept {
mImpl->mShadowSamplingQuality = quality;
return *this;
}
template<typename T, typename>
Material::Builder& Material::Builder::constant(const char* name, size_t nameLength, T value) {
FILAMENT_CHECK_PRECONDITION(name != nullptr) << "name cannot be null";
@@ -327,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,
@@ -335,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;
@@ -354,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) {
@@ -556,7 +580,7 @@ Program FMaterial::getProgramWithVariants(
<< "The material '" << mName.c_str()
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
"vertex shader (variant="
<< +variant.key << ", filtered=" << +vertexVariant.key << ").";
<< variant.key << ", filtered=" << vertexVariant.key << ").";
/*
* Fragment shader
@@ -571,7 +595,7 @@ Program FMaterial::getProgramWithVariants(
<< "The material '" << mName.c_str()
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
"fragment shader (variant="
<< +variant.key << ", filtered=" << +fragmentVariant.key << ").";
<< variant.key << ", filtered=" << ").";
Program program;
program.shader(ShaderStage::VERTEX, vsBuilder.data(), vsBuilder.size())
@@ -608,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 {
@@ -748,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();
}
}
@@ -1005,11 +951,7 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
(int)engine.getConfig().stereoscopicEyeCount });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT,
builder->mShBandsCount });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD,
(int32_t)builder->mShadowSamplingQuality });
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, builder->mShBandsCount });
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
// The actual value of this spec-constant is set in the OpenGLDriver backend.
mSpecializationConstants.push_back({
@@ -1086,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);
}
}
}
}
+3 -4
View File
@@ -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>>;
-5
View File
@@ -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);
});
-4
View File
@@ -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);
+1 -2
View File
@@ -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++) {
-2
View File
@@ -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);
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.56.5"
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.5/filament-v1.56.5-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 = {
+5 -8
View File
@@ -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
@@ -81,9 +81,7 @@ enum class ReservedSpecializationConstants : uint8_t {
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
CONFIG_SH_BANDS_COUNT = 9,
CONFIG_SHADOW_SAMPLING_METHOD = 10
// check CONFIG_MAX_RESERVED_SPEC_CONSTANTS below
CONFIG_SH_BANDS_COUNT = 9
};
enum class PushConstantIds : uint8_t {
@@ -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
+2 -42
View File
@@ -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
@@ -337,9 +337,6 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
generateSpecializationConstant(out, "CONFIG_SH_BANDS_COUNT",
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, 3);
generateSpecializationConstant(out, "CONFIG_SHADOW_SAMPLING_METHOD",
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD, 1);
// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
// be explicitly, statically defined (as in #define). Otherwise (using const int for
// example), we'd run into a GPU crash.
+5 -7
View File
@@ -660,13 +660,11 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
CodeGenerator::generateDepthShaderMain(fs, ShaderStage::FRAGMENT);
} else {
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
if (material.isLit) {
if (filament::Variant::isSSRVariant(variant)) {
CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT);
} else {
CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant,
material.shading,material.hasCustomSurfaceShading);
}
if (filament::Variant::isSSRVariant(variant)) {
CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT);
} else if (material.isLit) {
CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant,
material.shading,material.hasCustomSurfaceShading);
} else {
CodeGenerator::generateShaderUnlit(fs, ShaderStage::FRAGMENT, variant,
material.hasShadowMultiplier);
+1 -1
View File
@@ -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) {
+3 -3
View File
@@ -63,7 +63,7 @@ using filamat::ChunkType;
using utils::FixedCapacityVector;
static auto const error = [](int line, std::string const& uri) {
utils::slog.e << "[matdbg] DebugServer: 404 at line " << line << ": " << uri << utils::io::endl;
utils::slog.e << "DebugServer: 404 at line " << line << ": " << uri << utils::io::endl;
return false;
};
@@ -80,7 +80,7 @@ MaterialRecord const* ApiHandler::getMaterialRecord(struct mg_request_info const
bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
struct mg_request_info const* request) {
auto const softError = [conn, request](char const* msg) {
utils::slog.e << "[matdbg] DebugServer: " << msg << ": " << request->query_string << utils::io::endl;
utils::slog.e << "DebugServer: " << msg << ": " << request->query_string << utils::io::endl;
mg_printf(conn, kErrorHeader.data(), "application/txt");
mg_write(conn, msg, strlen(msg));
return true;
@@ -266,7 +266,7 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
while (readLen < msgLen) {
int const res = mg_read(conn, buf, sizeof(buf));
if (res < 0) {
utils::slog.e << "[matdbg] civet error parsing /api/edit body: " << res << utils::io::endl;
utils::slog.e << "civet error parsing /api/edit body: " << res << utils::io::endl;
break;
}
if (res == 0) {
+5 -5
View File
@@ -115,7 +115,7 @@ public:
return true;
}
#endif
slog.e << "[matdbg] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
slog.e << "DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
return false;
}
private:
@@ -156,7 +156,7 @@ DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) {
if (!mServer->getContext()) {
delete mServer;
mServer = nullptr;
slog.e << "[matdbg] Unable to start DebugServer, see civetweb.txt for details." << io::endl;
slog.e << "Unable to start DebugServer, see civetweb.txt for details." << io::endl;
return;
}
@@ -166,7 +166,7 @@ DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) {
mServer->addHandler("/api", mApiHandler);
mServer->addHandler("", mFileHandler);
slog.i << "[matdbg] DebugServer listening at http://localhost:" << port << io::endl;
slog.i << "DebugServer listening at http://localhost:" << port << io::endl;
filamat::GLSLTools::init();
}
@@ -189,7 +189,7 @@ MaterialKey
DebugServer::addMaterial(const CString& name, const void* data, size_t size, void* userdata) {
filaflat::ChunkContainer* container = new filaflat::ChunkContainer(data, size);
if (!container->parse()) {
slog.e << "[matdbg] DebugServer: unable to parse material package: " << name.c_str() << io::endl;
slog.e << "DebugServer: unable to parse material package: " << name.c_str() << io::endl;
return {};
}
@@ -236,7 +236,7 @@ void DebugServer::updateActiveVariants() {
bool DebugServer::handleEditCommand(const MaterialKey& key, backend::Backend api, int shaderIndex,
const char* source, size_t size) {
const auto error = [](int line) {
slog.e << "[matdbg] DebugServer: Unable to apply shader edit at line " << line << io::endl;
slog.e << "DebugServer: Unable to apply shader edit at line " << line << io::endl;
return false;
};
+6 -6
View File
@@ -200,7 +200,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS, &binary, &diagnostic);
spvContextDestroy(context);
if (error) {
slog.e << "[matdbg] ShaderReplacer spirv-as failed (spv_result_t: " << error << ")" << io::endl;
slog.e << "ShaderReplacer spirv-as failed (spv_result_t: " << error << ")" << io::endl;
spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic);
return false;
@@ -227,7 +227,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
const bool ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
if (!ok) {
slog.e << "[matdbg] ShaderReplacer parse:\n" << tShader.getInfoLog() << io::endl;
slog.e << "ShaderReplacer parse:\n" << tShader.getInfoLog() << io::endl;
return false;
}
@@ -235,7 +235,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
program.addShader(&tShader);
const bool linkOk = program.link(msg);
if (!linkOk) {
slog.e << "[matdbg] ShaderReplacer link:\n" << program.getInfoLog() << io::endl;
slog.e << "ShaderReplacer link:\n" << program.getInfoLog() << io::endl;
return false;
}
@@ -247,7 +247,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
source = (const char*) spirv.data();
sourceLength = spirv.size() * 4;
slog.i << "[matdbg] Success re-generating SPIR-V. (" << sourceLength << " bytes)" << io::endl;
slog.i << "Success re-generating SPIR-V. (" << sourceLength << " bytes)" << io::endl;
// Clone all chunks except Dictionary* and Material*.
filaflat::ChunkContainer const& cc = mOriginalPackage;
@@ -349,7 +349,7 @@ void ShaderIndex::replaceShader(backend::ShaderModel model, Variant variant,
return;
}
}
slog.e << "[matdbg] Failed to replace shader." << io::endl;
slog.e << "Failed to replace shader." << io::endl;
}
BlobIndex::BlobIndex(ChunkType dictTag, ChunkType matTag, const filaflat::ChunkContainer& cc) :
@@ -426,7 +426,7 @@ void BlobIndex::replaceShader(ShaderModel model, Variant variant,
return;
}
}
slog.e << "[matdbg] Unable to replace shader." << io::endl;
slog.e << "Unable to replace shader." << io::endl;
}
} // namespace filament::matdbg
-2
View File
@@ -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);
};
-2
View File
@@ -3,7 +3,6 @@
highp mat3 shading_tangentToWorld; // TBN matrix
highp vec3 shading_position; // position of the fragment in world space
vec3 shading_view; // normalized vector from the fragment to the eye
#if defined(HAS_ATTRIBUTE_TANGENTS)
vec3 shading_normal; // normalized transformed normal, in world space
vec3 shading_geometricNormal; // normalized geometric normal, in world space
vec3 shading_reflected; // reflection of view about normal
@@ -16,6 +15,5 @@ highp vec3 shading_position; // position of the fragment in world space
#if defined(MATERIAL_HAS_CLEAR_COAT)
vec3 shading_clearCoatNormal; // normalized clear coat layer normal, in world space
#endif
#endif
highp vec2 shading_normalizedViewportCoord;
-4
View File
@@ -63,8 +63,6 @@ bool isPerspectiveProjection() {
return frameUniforms.clipFromViewMatrix[2].w != 0.0;
}
#if defined(HAS_ATTRIBUTE_TANGENTS)
/** @public-api */
vec3 getWorldNormalVector() {
return shading_normal;
@@ -85,8 +83,6 @@ float getNdotV() {
return shading_NoV;
}
#endif
highp vec3 getNormalizedPhysicalViewportCoord() {
// make sure to handle our reversed-z
return vec3(shading_normalizedViewportCoord, gl_FragCoord.z);
+11 -6
View File
@@ -8,8 +8,10 @@
#define SHADOW_SAMPLING_RUNTIME_DPCF 2u
#define SHADOW_SAMPLING_RUNTIME_PCSS 3u
// TODO: this should be user-settable, maybe at the material level
#define SHADOW_SAMPLING_PCF_HARD 0
#define SHADOW_SAMPLING_PCF_LOW 1
#define SHADOW_SAMPLING_METHOD SHADOW_SAMPLING_PCF_LOW
//------------------------------------------------------------------------------
// PCF Shadow Sampling
@@ -27,6 +29,7 @@ float sampleDepth(const mediump sampler2DArrayShadow map,
return texture(map, vec4(uv, layer, saturate(depth)));
}
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
// use hardware assisted PCF
float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
@@ -35,7 +38,9 @@ float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
return sampleDepth(map, scissorNormalized, layer, position.xy, position.z);
}
#endif
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
// use hardware assisted PCF + 3x3 gaussian filter
float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
@@ -72,6 +77,7 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
sum += uw.y * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.y), depth);
return sum * (1.0 / 16.0);
}
#endif
// use manual PCF
float ShadowSample_PCF(const mediump sampler2DArray map,
@@ -517,12 +523,11 @@ float shadow(const bool DIRECTIONAL,
const int index, highp vec4 shadowPosition, highp float zLight) {
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
uint layer = shadowUniforms.shadows[index].layer;
if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD) {
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
} else if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW) {
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
}
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
#endif
}
// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.56.5",
"version": "1.56.0",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",