diff --git a/README.md b/README.md index 443168d2a6..f0e9ca349d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.54.0' + implementation 'com.google.android.filament:filament-android:1.54.1' } ``` @@ -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.54.0' +pod 'Filament', '~> 1.54.1' ``` ### Snapshots diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index c0680a5505..0bad42c932 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,10 @@ 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.54.2 + +- Add a `name` API to Filament objects for debugging handle use-after-free assertions + ## v1.54.1 diff --git a/android/gradle.properties b/android/gradle.properties index f8284a4f77..994ce21404 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.54.0 +VERSION_NAME=1.54.1 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 96d1b57a19..87eee91494 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -61,6 +61,7 @@ set(SRCS src/Engine.cpp src/Exposure.cpp src/Fence.cpp + src/FilamentBuilder.cpp src/FrameInfo.cpp src/FrameSkipper.cpp src/Froxelizer.cpp diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index e20f76bc4b..a2bb01637e 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1150,7 +1150,7 @@ struct RasterState { bool inverseFrontFaces : 1; // 31 //! padding, must be 0 - bool depthClamp : 1; // 32 + uint8_t padding : 1; // 32 }; uint32_t u = 0; }; diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index b3c9809044..591df4c346 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -162,6 +162,10 @@ DECL_DRIVER_API_0(finish) // reset state tracking, if the driver does any state tracking (e.g. GL) DECL_DRIVER_API_0(resetState) +DECL_DRIVER_API_N(setDebugTag, + backend::HandleBase::HandleId, handleId, + utils::CString, tag) + /* * Creating driver objects * ----------------------- @@ -354,7 +358,6 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported) DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported) -DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported) DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers) DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize) DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams) diff --git a/filament/backend/include/private/backend/HandleAllocator.h b/filament/backend/include/private/backend/HandleAllocator.h index 03fccef6e0..a829e56550 100644 --- a/filament/backend/include/private/backend/HandleAllocator.h +++ b/filament/backend/include/private/backend/HandleAllocator.h @@ -20,11 +20,12 @@ #include #include +#include #include +#include #include #include #include -#include #include @@ -173,8 +174,10 @@ public: uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT; auto const pNode = static_cast(p); uint8_t const expectedAge = pNode[-1].age; - FILAMENT_CHECK_POSTCONDITION(expectedAge == age) << - "use-after-free of Handle with id=" << handle.getId(); + // getHandleTag() is only called if the check fails. + FILAMENT_CHECK_POSTCONDITION(expectedAge == age) + << "use-after-free of Handle with id=" << handle.getId() + << ", tag=" << getHandleTag(handle.getId()).c_str_safe(); } } @@ -201,6 +204,34 @@ public: return handle_cast(const_cast&>(handle)); } + void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept { + // TODO: for now, only pool handles check for use-after-free, so we only keep tags for + // those + if (isPoolHandle(id)) { + // Truncate the tag's age to N bits. + constexpr uint8_t N = 2; // support a history of 4 tags + constexpr uint8_t mask = (1 << N) - 1; + + uint8_t const age = (id & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT; + uint8_t const newAge = age & mask; + uint32_t const key = (id & ~HANDLE_AGE_MASK) | (newAge << HANDLE_AGE_SHIFT); + + // This line is the costly part. In the future, we could potentially use a custom + // allocator. + mDebugTags[key] = std::move(tag); + } + } + + utils::CString getHandleTag(HandleBase::HandleId id) const noexcept { + if (!isPoolHandle(id)) { + return "(no tag)"; + } + if (auto pos = mDebugTags.find(id); pos != mDebugTags.end()) { + return pos->second; + } + return "(no tag)"; + } + private: template @@ -363,6 +394,7 @@ private: // Below is only used when running out of space in the HandleArena mutable utils::Mutex mLock; tsl::robin_map mOverflowMap; + tsl::robin_map mDebugTags; HandleBase::HandleId mId = 0; bool mUseAfterFreeCheckDisabled = false; }; diff --git a/filament/backend/src/HandleAllocator.cpp b/filament/backend/src/HandleAllocator.cpp index 07d028d9d4..6cdcaa4af4 100644 --- a/filament/backend/src/HandleAllocator.cpp +++ b/filament/backend/src/HandleAllocator.cpp @@ -80,6 +80,9 @@ HandleAllocator::HandleAllocator(const char* name, size_t size, bool disableUseAfterFreeCheck) noexcept : mHandleArena(name, size, disableUseAfterFreeCheck), mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) { + // Reserve initial space for debug tags. This prevents excessive calls to malloc when the first + // few tags are set. + mDebugTags.reserve(512); } template diff --git a/filament/backend/src/metal/MetalBuffer.h b/filament/backend/src/metal/MetalBuffer.h index 69de2a5b73..da0cfa55bf 100644 --- a/filament/backend/src/metal/MetalBuffer.h +++ b/filament/backend/src/metal/MetalBuffer.h @@ -160,6 +160,8 @@ public: size_t size, bool forceGpuBuffer = false); ~MetalBuffer(); + [[nodiscard]] bool wasAllocationSuccessful() const noexcept { return mBuffer || mCpuBuffer; } + MetalBuffer(const MetalBuffer& rhs) = delete; MetalBuffer& operator=(const MetalBuffer& rhs) = delete; diff --git a/filament/backend/src/metal/MetalBuffer.mm b/filament/backend/src/metal/MetalBuffer.mm index 0d8556b036..d6f68c33af 100644 --- a/filament/backend/src/metal/MetalBuffer.mm +++ b/filament/backend/src/metal/MetalBuffer.mm @@ -56,8 +56,8 @@ MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, mBuffer = { [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate], TrackedMetalBuffer::Type::GENERIC }; } - FILAMENT_CHECK_POSTCONDITION(mBuffer) - << "Could not allocate Metal buffer of size " << size << "."; + // mBuffer might fail to be allocated. Clients can check for this by calling + // wasAllocationSuccessful(). } MetalBuffer::~MetalBuffer() { diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index 5ab2fccd27..73e674d11b 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -166,7 +166,6 @@ struct MetalContext { std::array ssboState; CullModeStateTracker cullModeState; WindingStateTracker windingState; - DepthClampStateTracker depthClampState; Handle currentRenderPrimitive; // State caches. diff --git a/filament/backend/src/metal/MetalDriver.h b/filament/backend/src/metal/MetalDriver.h index 359ef53d88..7190c518b8 100644 --- a/filament/backend/src/metal/MetalDriver.h +++ b/filament/backend/src/metal/MetalDriver.h @@ -58,7 +58,6 @@ class MetalDriver final : public DriverBase { public: static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig); - void runAtNextTick(const std::function& fn) noexcept; private: @@ -75,10 +74,12 @@ private: /* * Tasks run regularly on the driver thread. + * Not thread-safe; tasks are run from the driver thead and must be enqueued from the driver + * thread. */ + void runAtNextTick(const std::function& fn) noexcept; void executeTickOps() noexcept; std::vector> mTickOps; - std::mutex mTickOpsLock; // Tasks regularly executed on the driver thread after a command buffer has completed struct DeferredTask { diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index afb3ce2d7c..fd6b45e30a 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -405,17 +405,40 @@ void MetalDriver::createVertexBufferR(Handle vbh, uint32_t vertexCount, Handle vbih) { MetalVertexBufferInfo const* const vbi = handle_cast(vbih); construct_handle(vbh, *mContext, vertexCount, vbi->bufferCount, vbih); + // No actual GPU memory is allocated here, so no need to check for allocation success. } void MetalDriver::createIndexBufferR(Handle ibh, ElementType elementType, uint32_t indexCount, BufferUsage usage) { - auto elementSize = (uint8_t) getElementTypeSize(elementType); - construct_handle(ibh, *mContext, usage, elementSize, indexCount); + auto elementSize = (uint8_t)getElementTypeSize(elementType); + auto* indexBuffer = + construct_handle(ibh, *mContext, usage, elementSize, indexCount); + auto& buffer = indexBuffer->buffer; + // If the allocation was not successful, postpone the error message until the next tick, to give + // Filament a chance to call setDebugTag on the handle; this way we get a nicer error message. + if (UTILS_UNLIKELY(!buffer.wasAllocationSuccessful())) { + const size_t byteCount = buffer.getSize(); + runAtNextTick([byteCount, this, ibh]() { + FILAMENT_CHECK_POSTCONDITION(false) + << "Could not allocate Metal index buffer of size " << byteCount + << ", tag=" << mHandleAllocator.getHandleTag(ibh.getId()).c_str_safe(); + }); + } } void MetalDriver::createBufferObjectR(Handle boh, uint32_t byteCount, BufferObjectBinding bindingType, BufferUsage usage) { - construct_handle(boh, *mContext, bindingType, usage, byteCount); + auto* bufferObject = + construct_handle(boh, *mContext, bindingType, usage, byteCount); + // If the allocation was not successful, postpone the error message until the next tick, to give + // Filament a chance to call setDebugTag on the handle; this way we get a nicer error message. + if (UTILS_UNLIKELY(!bufferObject->getBuffer()->wasAllocationSuccessful())) { + runAtNextTick([byteCount, this, boh]() { + FILAMENT_CHECK_POSTCONDITION(false) + << "Could not allocate Metal buffer of size " << byteCount + << ", tag=" << mHandleAllocator.getHandleTag(boh.getId()).c_str_safe(); + }); + } } void MetalDriver::createTextureR(Handle th, SamplerType target, uint8_t levels, @@ -1061,10 +1084,6 @@ bool MetalDriver::isProtectedTexturesSupported() { return false; } -bool MetalDriver::isDepthClampSupported() { - return true; -} - bool MetalDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: @@ -1961,13 +1980,6 @@ void MetalDriver::bindPipeline(PipelineState const& ps) { [mContext->currentRenderPassEncoder setFrontFacingWinding:winding]; } - // depth clip mode - 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. DepthStencilState depthState; if (depthAttachment) { @@ -2311,16 +2323,17 @@ void MetalDriver::enumerateBoundBuffers(BufferObjectBinding bindingType, void MetalDriver::resetState(int) { } +void MetalDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { + mHandleAllocator.associateTagToHandle(handleId, std::move(tag)); +} + void MetalDriver::runAtNextTick(const std::function& fn) noexcept { - std::lock_guard const lock(mTickOpsLock); mTickOps.push_back(fn); } void MetalDriver::executeTickOps() noexcept { std::vector> ops; - mTickOpsLock.lock(); std::swap(ops, mTickOps); - mTickOpsLock.unlock(); for (const auto& f : ops) { f(); } diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index f2ccebdecc..dbfcff07b9 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -253,10 +253,6 @@ void MetalSwapChain::present() { } } -#ifndef FILAMENT_RELEASE_PRESENT_DRAWABLE_MAIN_THREAD -#define FILAMENT_RELEASE_PRESENT_DRAWABLE_MAIN_THREAD 1 -#endif - class PresentDrawableData { public: PresentDrawableData() = delete; @@ -275,14 +271,10 @@ public: [that->mDrawable present]; } -#if FILAMENT_RELEASE_PRESENT_DRAWABLE_MAIN_THREAD == 1 // mDrawable is acquired on the driver thread. Typically, we would release this object on // the same thread, but after receiving consistent crash reports from within // [CAMetalDrawable dealloc], we suspect this object requires releasing on the main thread. dispatch_async(dispatch_get_main_queue(), ^{ cleanupAndDestroy(that); }); -#else - that->mDriver->runAtNextTick([that]() { cleanupAndDestroy(that); }); -#endif } private: diff --git a/filament/backend/src/metal/MetalState.h b/filament/backend/src/metal/MetalState.h index 2f5579d060..0f604e264b 100644 --- a/filament/backend/src/metal/MetalState.h +++ b/filament/backend/src/metal/MetalState.h @@ -379,7 +379,6 @@ using SamplerStateCache = StateCache, SamplerS using CullModeStateTracker = StateTracker; using WindingStateTracker = StateTracker; -using DepthClampStateTracker = StateTracker; // Argument encoder diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index 54f8d41135..a4586c16b8 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -208,10 +208,6 @@ bool NoopDriver::isProtectedTexturesSupported() { return true; } -bool NoopDriver::isDepthClampSupported() { - return false; -} - bool NoopDriver::isWorkaroundNeeded(Workaround) { return false; } @@ -413,4 +409,7 @@ void NoopDriver::bindDescriptorSet( backend::DescriptorSetOffsetArray&& offsets) { } +void NoopDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { +} + } // namespace filament diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index a7933407bb..66327633f1 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -676,7 +676,6 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor #ifndef __EMSCRIPTEN__ ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); #endif - ext->EXT_depth_clamp = exts.has("GL_EXT_depth_clamp"sv); ext->EXT_discard_framebuffer = exts.has("GL_EXT_discard_framebuffer"sv); #ifndef __EMSCRIPTEN__ ext->EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv); @@ -747,7 +746,6 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor) ext->EXT_color_buffer_half_float = true; // Assumes core profile. ext->EXT_clip_cull_distance = true; ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); - ext->EXT_depth_clamp = true; ext->EXT_discard_framebuffer = false; ext->EXT_disjoint_timer_query = true; ext->EXT_multisampled_render_to_texture = false; diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 4544ca104f..8659ba3d2a 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -224,9 +224,8 @@ public: bool EXT_color_buffer_float; bool EXT_color_buffer_half_float; bool EXT_debug_marker; - bool EXT_depth_clamp; - bool EXT_discard_framebuffer; bool EXT_disjoint_timer_query; + bool EXT_discard_framebuffer; bool EXT_multisampled_render_to_texture2; bool EXT_multisampled_render_to_texture; bool EXT_protected_textures; @@ -244,10 +243,10 @@ public: bool KHR_parallel_shader_compile; bool KHR_texture_compression_astc_hdr; bool KHR_texture_compression_astc_ldr; - bool OES_EGL_image_external_essl3; - bool OES_depth24; bool OES_depth_texture; + bool OES_depth24; bool OES_packed_depth_stencil; + bool OES_EGL_image_external_essl3; bool OES_rgb8_rgba8; bool OES_standard_derivatives; bool OES_texture_npot; @@ -623,7 +622,6 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT #ifdef BACKEND_OPENGL_VERSION_GL case GL_PROGRAM_POINT_SIZE: index = 10; break; #endif - case GL_DEPTH_CLAMP: index = 11; break; default: break; } assert_invariant(index < state.enables.caps.size()); diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 321ea0e81f..43d774b201 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -462,14 +462,6 @@ void OpenGLDriver::setRasterState(RasterState rs) noexcept { } else { gl.disable(GL_SAMPLE_ALPHA_TO_COVERAGE); } - - if (gl.ext.EXT_depth_clamp) { - if (rs.depthClamp) { - gl.enable(GL_DEPTH_CLAMP); - } else { - gl.disable(GL_DEPTH_CLAMP); - } - } } void OpenGLDriver::setStencilState(StencilState ss) noexcept { @@ -2254,10 +2246,6 @@ bool OpenGLDriver::isProtectedTexturesSupported() { return getContext().ext.EXT_protected_textures; } -bool OpenGLDriver::isDepthClampSupported() { - return getContext().ext.EXT_depth_clamp; -} - bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: @@ -2349,6 +2337,10 @@ void OpenGLDriver::makeCurrent(Handle schDraw, Handle // Updating driver objects // ------------------------------------------------------------------------------------------------ +void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { + mHandleAllocator.associateTagToHandle(handleId, std::move(tag)); +} + void OpenGLDriver::setVertexBufferObject(Handle vbh, uint32_t index, Handle boh) { DEBUG_MARKER() diff --git a/filament/backend/src/opengl/gl_headers.h b/filament/backend/src/opengl/gl_headers.h index 04ad63ff6a..569c8ed285 100644 --- a/filament/backend/src/opengl/gl_headers.h +++ b/filament/backend/src/opengl/gl_headers.h @@ -201,12 +201,6 @@ using namespace glext; # define GL_CLIP_DISTANCE1 0x3001 #endif -#if defined(GL_EXT_depth_clamp) -# define GL_DEPTH_CLAMP GL_DEPTH_CLAMP_EXT -#else -# define GL_DEPTH_CLAMP 0x864F -#endif - #if defined(GL_KHR_debug) # define GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_KHR # define GL_DEBUG_OUTPUT_SYNCHRONOUS GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 46fe475612..9f506e03f7 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -125,10 +125,6 @@ public: return mPhysicalDeviceFeatures.imageCubeArray == VK_TRUE; } - inline bool isDepthClampSupported() const noexcept { - return mPhysicalDeviceFeatures.depthClamp == VK_TRUE; - } - inline bool isDebugMarkersSupported() const noexcept { return mDebugMarkersSupported; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 643c7d87bd..673af25691 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1038,10 +1038,6 @@ bool VulkanDriver::isProtectedTexturesSupported() { return false; } -bool VulkanDriver::isDepthClampSupported() { - return mContext.isDepthClampSupported(); -} - bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: { @@ -1827,8 +1823,6 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { .dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha), .colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0), .rasterizationSamples = rt->getSamples(), - .depthClamp = rasterState.depthClamp, - .reserved = 0, .colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass), .colorBlendOp = rasterState.blendEquationRGB, .alphaBlendOp = rasterState.blendEquationAlpha, @@ -2020,6 +2014,10 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons void VulkanDriver::resetState(int) { } +void VulkanDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { + mResourceAllocator.associateHandle(handleId, std::move(tag)); +} + // explicit instantiation of the Dispatcher template class ConcreteDispatcher; diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 4c440a0085..27f70e7840 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -184,7 +184,6 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n vkRaster.polygonMode = VK_POLYGON_MODE_FILL; vkRaster.cullMode = raster.cullMode; vkRaster.frontFace = raster.frontFace; - vkRaster.depthClampEnable = raster.depthClamp; vkRaster.depthBiasEnable = raster.depthBiasEnable; vkRaster.depthBiasConstantFactor = raster.depthBiasConstantFactor; vkRaster.depthBiasClamp = 0.0f; diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index 985574b74c..e6816497c0 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -90,9 +90,7 @@ public: VkBlendFactor srcAlphaBlendFactor : 5; VkBlendFactor dstAlphaBlendFactor : 5; VkColorComponentFlags colorWriteMask : 4; - uint8_t rasterizationSamples : 4;// offset = 4 bytes - uint8_t depthClamp : 1; - uint8_t reserved : 3; + uint8_t rasterizationSamples; // offset = 4 bytes uint8_t colorTargetCount; // offset = 5 bytes BlendEquation colorBlendOp : 4; // offset = 6 bytes BlendEquation alphaBlendOp : 4; diff --git a/filament/backend/src/vulkan/VulkanResourceAllocator.h b/filament/backend/src/vulkan/VulkanResourceAllocator.h index 04187658b7..572aeed4f7 100644 --- a/filament/backend/src/vulkan/VulkanResourceAllocator.h +++ b/filament/backend/src/vulkan/VulkanResourceAllocator.h @@ -105,6 +105,10 @@ public: mHandleAllocatorImpl.deallocate(handle, obj); } + inline void associateHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept { + mHandleAllocatorImpl.associateTagToHandle(id, std::move(tag)); + } + private: AllocatorImpl mHandleAllocatorImpl; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index 2e88542080..b4152807cc 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -325,7 +325,6 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice, // We could simply enable all supported features, but since that may have performance // consequences let's just enable the features we need. VkPhysicalDeviceFeatures enabledFeatures{ - .depthClamp = features.depthClamp, .samplerAnisotropy = features.samplerAnisotropy, .textureCompressionETC2 = features.textureCompressionETC2, .textureCompressionBC = features.textureCompressionBC, diff --git a/filament/include/filament/BufferObject.h b/filament/include/filament/BufferObject.h index 74a4b1ff39..8c76719c85 100644 --- a/filament/include/filament/BufferObject.h +++ b/filament/include/filament/BufferObject.h @@ -54,7 +54,7 @@ public: using BufferDescriptor = backend::BufferDescriptor; using BindingType = backend::BufferObjectBinding; - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -78,6 +78,21 @@ public: */ Builder& bindingType(BindingType bindingType) noexcept; + /** + * Associate an optional name with this BufferObject for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this BufferObject + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the BufferObject and returns a pointer to it. After creation, the buffer * object is uninitialized. Use BufferObject::setBuffer() to initialize it. diff --git a/filament/include/filament/FilamentAPI.h b/filament/include/filament/FilamentAPI.h index 19d6ba246a..7a6f16d630 100644 --- a/filament/include/filament/FilamentAPI.h +++ b/filament/include/filament/FilamentAPI.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -54,6 +55,22 @@ public: template using BuilderBase = utils::PrivateImplementation; +void builderMakeName(utils::CString& outName, const char* name, size_t len) noexcept; + +template +class UTILS_PUBLIC BuilderNameMixin { +public: + Builder& name(const char* name, size_t len) noexcept { + builderMakeName(mName, name, len); + return static_cast(*this); + } + + utils::CString const& getName() const noexcept { return mName; } + +private: + utils::CString mName; +}; + } // namespace filament #endif // TNT_FILAMENT_FILAMENTAPI_H diff --git a/filament/include/filament/IndexBuffer.h b/filament/include/filament/IndexBuffer.h index 35b8a10ef2..ff29e1f44d 100644 --- a/filament/include/filament/IndexBuffer.h +++ b/filament/include/filament/IndexBuffer.h @@ -59,7 +59,7 @@ public: UINT = uint8_t(backend::ElementType::UINT), //!< 32-bit indices }; - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -83,6 +83,21 @@ public: */ Builder& bufferType(IndexType indexType) noexcept; + /** + * Associate an optional name with this IndexBuffer for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this IndexBuffer + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the IndexBuffer object and returns a pointer to it. After creation, the index * buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer. diff --git a/filament/include/filament/InstanceBuffer.h b/filament/include/filament/InstanceBuffer.h index 2135152d88..843c7983bb 100644 --- a/filament/include/filament/InstanceBuffer.h +++ b/filament/include/filament/InstanceBuffer.h @@ -38,7 +38,7 @@ class UTILS_PUBLIC InstanceBuffer : public FilamentAPI { struct BuilderDetails; public: - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: @@ -70,6 +70,21 @@ public: */ Builder& localTransforms(math::mat4f const* UTILS_NULLABLE localTransforms) noexcept; + /** + * Associate an optional name with this InstanceBuffer for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this InstanceBuffer + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the InstanceBuffer object and returns a pointer to it. */ diff --git a/filament/include/filament/MorphTargetBuffer.h b/filament/include/filament/MorphTargetBuffer.h index 655bb8d848..cb77bb79c8 100644 --- a/filament/include/filament/MorphTargetBuffer.h +++ b/filament/include/filament/MorphTargetBuffer.h @@ -39,7 +39,7 @@ class UTILS_PUBLIC MorphTargetBuffer : public FilamentAPI { struct BuilderDetails; public: - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -63,6 +63,21 @@ public: */ Builder& count(size_t count) noexcept; + /** + * Associate an optional name with this MorphTargetBuffer for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this MorphTargetBuffer + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the MorphTargetBuffer object and returns a pointer to it. * diff --git a/filament/include/filament/SkinningBuffer.h b/filament/include/filament/SkinningBuffer.h index 36ae30ed43..27b13191e5 100644 --- a/filament/include/filament/SkinningBuffer.h +++ b/filament/include/filament/SkinningBuffer.h @@ -39,7 +39,7 @@ class UTILS_PUBLIC SkinningBuffer : public FilamentAPI { struct BuilderDetails; public: - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -69,6 +69,21 @@ public: */ Builder& initialize(bool initialize = true) noexcept; + /** + * Associate an optional name with this SkinningBuffer for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this SkinningBuffer + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the SkinningBuffer object and returns a pointer to it. * diff --git a/filament/include/filament/Stream.h b/filament/include/filament/Stream.h index 6cafbacc8b..883a8ccab3 100644 --- a/filament/include/filament/Stream.h +++ b/filament/include/filament/Stream.h @@ -94,7 +94,7 @@ public: * * To create a NATIVE stream, call the
stream
method on the builder. */ - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -136,6 +136,21 @@ public: */ Builder& height(uint32_t height) noexcept; + /** + * Associate an optional name with this Stream for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this Stream + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the Stream object and returns a pointer to it. * diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index 8a27f831c2..b351c42943 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -112,7 +112,7 @@ public: //! Use Builder to construct a Texture object instance - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -202,6 +202,21 @@ public: */ Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept; + /** + * Associate an optional name with this Texture for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this Texture + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the Texture object and returns a pointer to it. * diff --git a/filament/include/filament/VertexBuffer.h b/filament/include/filament/VertexBuffer.h index fccbd0046f..64106434ab 100644 --- a/filament/include/filament/VertexBuffer.h +++ b/filament/include/filament/VertexBuffer.h @@ -61,7 +61,7 @@ public: using AttributeType = backend::ElementType; using BufferDescriptor = backend::BufferDescriptor; - class Builder : public BuilderBase { + class Builder : public BuilderBase, public BuilderNameMixin { friend struct BuilderDetails; public: Builder() noexcept; @@ -158,6 +158,21 @@ public: */ Builder& advancedSkinning(bool enabled) noexcept; + /** + * Associate an optional name with this VertexBuffer for debugging purposes. + * + * name will show in error messages and should be kept as short as possible. The name is + * truncated to a maximum of 128 characters. + * + * The name string is copied during this method so clients may free its memory after + * the function returns. + * + * @param name A string to identify this VertexBuffer + * @param len Length of name, should be less than or equal to 128 + * @return This Builder, for chaining calls. + */ + // Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited + /** * Creates the VertexBuffer object and returns a pointer to it. * diff --git a/filament/src/FilamentBuilder.cpp b/filament/src/FilamentBuilder.cpp new file mode 100644 index 0000000000..08f1cb3231 --- /dev/null +++ b/filament/src/FilamentBuilder.cpp @@ -0,0 +1,31 @@ +/* + * 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 + +#include + +namespace filament { + +void builderMakeName(utils::CString& outName, const char* name, size_t len) noexcept { + if (!name) { + return; + } + size_t const length = std::min(len, size_t { 128u }); + outName = utils::CString(name, length); +} + +} // namespace filament diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index a5acd48177..680ae50656 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -3204,6 +3204,7 @@ FrameGraphId PostProcessManager::resolve(FrameGraph& fg, assert_invariant(dst); assert_invariant(srcDesc.format == dstDesc.format); assert_invariant(srcDesc.width == dstDesc.width && srcDesc.height == dstDesc.height); + assert_invariant(srcDesc.samples > 1 && dstDesc.samples <= 1); driver.resolve( dst, dstSubDesc.level, dstSubDesc.layer, src, srcSubDesc.level, srcSubDesc.layer); diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index f939a1eaba..fa50ce3f72 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -449,8 +449,7 @@ RenderPass::Command* RenderPass::instanceify(FEngine& engine, UTILS_ALWAYS_INLINE // This function exists only to make the code more readable. we want it inlined. inline // and we don't need it in the compilation unit void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* const UTILS_RESTRICT mi, - bool inverseFrontFaces, bool hasDepthClamp) noexcept { + FMaterialInstance const* const UTILS_RESTRICT mi, bool inverseFrontFaces) noexcept { FMaterial const * const UTILS_RESTRICT ma = mi->getMaterial(); variant = Variant::filterVariant(variant, ma->isVariantLit()); @@ -491,7 +490,6 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, cmdDraw.info.rasterState.colorWrite = mi->isColorWriteEnabled(); cmdDraw.info.rasterState.depthWrite = mi->isDepthWriteEnabled(); cmdDraw.info.rasterState.depthFunc = mi->getDepthFunc(); - cmdDraw.info.rasterState.depthClamp = hasDepthClamp; cmdDraw.info.materialVariant = variant; // we keep "RasterState::colorWrite" to the value set by material (could be disabled) } @@ -589,9 +587,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla bool const hasInstancedStereo = renderFlags & IS_INSTANCED_STEREOSCOPIC; - bool const hasDepthClamp = - renderFlags & HAS_DEPTH_CLAMP; - float const cameraPositionDotCameraForward = dot(cameraPosition, cameraForward); auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data(); @@ -612,7 +607,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla cmd.info.rasterState.depthWrite = true; cmd.info.rasterState.depthFunc = RasterState::DepthFunc::GE; cmd.info.rasterState.alphaToCoverage = false; - cmd.info.rasterState.depthClamp = hasDepthClamp; } for (uint32_t i = range.first; i < range.last; ++i) { @@ -728,8 +722,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla // morphing.morphTargetBuffer->getHwHandle() : SamplerGroupHandle{}; if constexpr (isColorPass) { - RenderPass::setupColorCommand(cmd, renderableVariant, mi, - inverseFrontFaces, hasDepthClamp); + RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces); const bool blendPass = Pass(cmd.key & PASS_MASK) == Pass::BLENDED; if (blendPass) { // TODO: at least for transparent objects, AABB should be per primitive diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 472fdc8e8d..9c2148ba42 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -285,7 +285,6 @@ public: static constexpr RenderFlags HAS_SHADOWING = 0x01; static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02; static constexpr RenderFlags IS_INSTANCED_STEREOSCOPIC = 0x04; - static constexpr RenderFlags HAS_DEPTH_CLAMP = 0x08; // Arena used for commands using Arena = utils::Arena< @@ -454,7 +453,7 @@ private: uint8_t instancedStereoEyeCount) noexcept; static void setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* mi, bool inverseFrontFaces, bool hasDepthClamp) noexcept; + FMaterialInstance const* mi, bool inverseFrontFaces) noexcept; static void updateSummedPrimitiveCounts( FScene::RenderableSoa& renderableData, utils::Range vr) noexcept; diff --git a/filament/src/RendererUtils.cpp b/filament/src/RendererUtils.cpp index d8560bb4b7..2e57af691f 100644 --- a/filament/src/RendererUtils.cpp +++ b/filament/src/RendererUtils.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -50,8 +51,9 @@ namespace filament { using namespace backend; using namespace math; -FrameGraphId RendererUtils::colorPass( +RendererUtils::ColorPassOutput RendererUtils::colorPass( FrameGraph& fg, const char* name, FEngine& engine, FView const& view, + ColorPassInput const& colorPassInput, FrameGraphTexture::Descriptor const& colorBufferDesc, ColorPassConfig const& config, PostProcessManager::ColorGradingConfig colorGradingConfig, RenderPass::Executor passExecutor) noexcept { @@ -67,8 +69,6 @@ FrameGraphId RendererUtils::colorPass( FrameGraphId structure; }; - Blackboard& blackboard = fg.getBlackboard(); - auto& colorPass = fg.addPass(name, [&](FrameGraph::Builder& builder, ColorPassData& data) { @@ -76,21 +76,21 @@ FrameGraphId RendererUtils::colorPass( TargetBufferFlags clearDepthFlags = config.clearFlags & TargetBufferFlags::DEPTH; TargetBufferFlags clearStencilFlags = config.clearFlags & TargetBufferFlags::STENCIL; - data.shadows = blackboard.get("shadows"); - data.ssao = blackboard.get("ssao"); - data.color = blackboard.get("color"); - data.depth = blackboard.get("depth"); + data.color = colorPassInput.linearColor; + data.depth = colorPassInput.depth; + data.shadows = colorPassInput.shadows; + data.ssao = colorPassInput.ssao; // Screen-space reflection or refractions if (config.hasScreenSpaceReflectionsOrRefractions) { - data.ssr = blackboard.get("ssr"); + data.ssr = colorPassInput.ssr; if (data.ssr) { data.ssr = builder.sample(data.ssr); } } if (config.hasContactShadows) { - data.structure = blackboard.get("structure"); + data.structure = colorPassInput.structure; assert_invariant(data.structure); data.structure = builder.sample(data.structure); } @@ -153,6 +153,8 @@ FrameGraphId RendererUtils::colorPass( } if (colorGradingConfig.asSubpass) { + assert_invariant(config.msaa <= 1); + assert_invariant(colorBufferDesc.samples <= 1); data.output = builder.createTexture("Tonemapped Buffer", { .width = colorBufferDesc.width, .height = colorBufferDesc.height, @@ -194,7 +196,6 @@ FrameGraphId RendererUtils::colorPass( .samples = config.msaa, .layerCount = static_cast(colorBufferDesc.depth), .clearFlags = clearColorFlags | clearDepthFlags | clearStencilFlags}); - blackboard["depth"] = data.depth; }, [=, passExecutor = std::move(passExecutor), &view, &engine](FrameGraphResources const& resources, ColorPassData const& data, DriverApi& driver) { @@ -260,24 +261,21 @@ FrameGraphId RendererUtils::colorPass( } ); - // when color grading is done as a subpass, the output of the color-pass is the ldr buffer - auto output = colorGradingConfig.asSubpass ? colorPass->output : colorPass->color; - - blackboard["color"] = output; - return output; + return { + .linearColor = colorPass->color, + .tonemappedColor = colorPass->output, // can be null + .depth = colorPass->depth + }; } -std::pair, bool> RendererUtils::refractionPass( +std::optional RendererUtils::refractionPass( FrameGraph& fg, FEngine& engine, FView const& view, + ColorPassInput colorPassInput, ColorPassConfig config, PostProcessManager::ScreenSpaceRefConfig const& ssrConfig, PostProcessManager::ColorGradingConfig colorGradingConfig, RenderPass const& pass) noexcept { - auto& blackboard = fg.getBlackboard(); - auto input = blackboard.get("color"); - FrameGraphId output; - // find the first refractive object in channel 2 RenderPass::Command const* const refraction = std::partition_point(pass.begin(), pass.end(), [](auto const& command) { @@ -292,23 +290,21 @@ std::pair, bool> RendererUtils::refractionPass( // if there wasn't any refractive object, just skip everything below. if (UTILS_UNLIKELY(hasScreenSpaceRefraction)) { - PostProcessManager& ppm = engine.getPostProcessManager(); - - // clear the color/depth buffers, which will orphan (and cull) the color pass - input.clear(); - blackboard.remove("color"); - blackboard.remove("depth"); - + assert_invariant(!colorPassInput.linearColor); + assert_invariant(!colorPassInput.depth); config.hasScreenSpaceReflectionsOrRefractions = true; - input = RendererUtils::colorPass(fg, "Color Pass (opaque)", engine, view, { + PostProcessManager& ppm = engine.getPostProcessManager(); + auto const opaquePassOutput = RendererUtils::colorPass(fg, + "Color Pass (opaque)", engine, view, colorPassInput, { // When rendering the opaques, we need to conserve the sample buffer, // so create a config that specifies the sample count. .width = config.physicalViewport.width, .height = config.physicalViewport.height, .samples = config.msaa, .format = config.hdrFormat - }, config, { .asSubpass = false }, + }, + config, { .asSubpass = false, .customResolve = false }, pass.getExecutor(pass.begin(), refraction)); @@ -317,13 +313,16 @@ std::pair, bool> RendererUtils::refractionPass( // in bound because only the descriptor 0 (frame uniforms) matters, and it's // present in both. PostProcessManager::generateMipmapSSR(ppm, fg, - input, ssrConfig.refraction, true, ssrConfig); + opaquePassOutput.linearColor, + ssrConfig.refraction, + true, ssrConfig); // Now we're doing the refraction pass proper. - // This uses the same framebuffer (color and depth) used by the opaque pass. This happens - // automatically because these are set in the Blackboard (they were set by the opaque - // pass). For this reason, `desc` below is only used in colorPass() for the width and - // height. + // This uses the same framebuffer (color and depth) used by the opaque pass. + // For this reason, the `colorBufferDesc` parameter of colorPass() below is only used for + // the width and height. + colorPassInput.linearColor = opaquePassOutput.linearColor; + colorPassInput.depth = opaquePassOutput.depth; // Since we're reusing the existing target we don't want to clear any of its buffer. // Important: if this target ended up being an imported target, then the clearFlags @@ -331,22 +330,25 @@ std::pair, bool> RendererUtils::refractionPass( // and we'd end up clearing the opaque pass. This scenario never happens because it is // prevented in Renderer.cpp's final blit. config.clearFlags = TargetBufferFlags::NONE; - output = RendererUtils::colorPass(fg, "Color Pass (transparent)", engine, view, { + auto transparentPassOutput = RendererUtils::colorPass(fg, "Color Pass (transparent)", + engine, view, colorPassInput, { .width = config.physicalViewport.width, .height = config.physicalViewport.height }, - config, colorGradingConfig, pass.getExecutor(refraction, pass.end())); + config, colorGradingConfig, + pass.getExecutor(refraction, pass.end())); if (config.msaa > 1 && !colorGradingConfig.asSubpass) { // We need to do a resolve here because later passes (such as color grading or DoF) will // need to sample from 'output'. However, because we have MSAA, we know we're not // sampleable. And this is because in the SSR case, we had to use a renderbuffer to // conserve the multi-sample buffer. - output = ppm.resolve(fg, "Resolved Color Buffer", output, { .levels = 1 }); + transparentPassOutput.linearColor = ppm.resolve(fg, "Resolved Color Buffer", + transparentPassOutput.linearColor, { .levels = 1 }); } - } else { - output = input; + return transparentPassOutput; } - return { output, hasScreenSpaceRefraction }; + + return std::nullopt; } UTILS_NOINLINE diff --git a/filament/src/RendererUtils.h b/filament/src/RendererUtils.h index 9b7e93cbc6..34ea7b0eda 100644 --- a/filament/src/RendererUtils.h +++ b/filament/src/RendererUtils.h @@ -21,14 +21,19 @@ #include "RenderPass.h" #include "fg/FrameGraphId.h" +#include "fg/FrameGraphTexture.h" + +#include #include #include +#include #include #include +#include #include namespace filament { @@ -71,15 +76,32 @@ public: bool screenSpaceReflectionHistoryNotReady; }; - static FrameGraphId colorPass( + struct ColorPassInput { + FrameGraphId linearColor; + FrameGraphId tonemappedColor; + FrameGraphId depth; + FrameGraphId shadows; + FrameGraphId ssao; + FrameGraphId ssr; + FrameGraphId structure; + }; + struct ColorPassOutput { + FrameGraphId linearColor; + FrameGraphId tonemappedColor; + FrameGraphId depth; + }; + + static ColorPassOutput colorPass( FrameGraph& fg, const char* name, FEngine& engine, FView const& view, + ColorPassInput const& colorPassInput, FrameGraphTexture::Descriptor const& colorBufferDesc, ColorPassConfig const& config, PostProcessManager::ColorGradingConfig colorGradingConfig, RenderPass::Executor passExecutor) noexcept; - static std::pair, bool> refractionPass( + static std::optional refractionPass( FrameGraph& fg, FEngine& engine, FView const& view, + ColorPassInput colorPassInput, ColorPassConfig config, PostProcessManager::ScreenSpaceRefConfig const& ssrConfig, PostProcessManager::ColorGradingConfig colorGradingConfig, diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index fd5d314580..ac0df6ed0d 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -829,13 +829,13 @@ ShadowMap::Corners ShadowMap::computeFrustumCorners( Corners const csViewFrustumCorners = { .vertices = { { -1, -1, far }, - { 1, -1, far }, - { -1, 1, far }, - { 1, 1, far }, + { 1, -1, far }, + { -1, 1, far }, + { 1, 1, far }, { -1, -1, near }, - { 1, -1, near }, - { -1, 1, near }, - { 1, 1, near }, + { 1, -1, near }, + { -1, 1, near }, + { 1, 1, near }, } }; diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index ef2be45c13..2229f6ade2 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -66,15 +66,15 @@ namespace filament { using namespace backend; using namespace math; -ShadowMapManager::ShadowMapManager(FEngine& engine) - : mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) { +// do this only if depth-clamp is available +static constexpr bool USE_DEPTH_CLAMP = false; + +ShadowMapManager::ShadowMapManager(FEngine& engine) { FDebugRegistry& debugRegistry = engine.getDebugRegistry(); debugRegistry.registerProperty("d.shadowmap.visualize_cascades", &engine.debug.shadowmap.visualize_cascades); debugRegistry.registerProperty("d.shadowmap.disable_light_frustum_align", &engine.debug.shadowmap.disable_light_frustum_align); - debugRegistry.registerProperty("d.shadowmap.depth_clamp", - &engine.debug.shadowmap.depth_clamp); } ShadowMapManager::~ShadowMapManager() { @@ -367,22 +367,7 @@ FrameGraphId ShadowMapManager::render(FEngine& engine, FrameG // generate and sort the commands for rendering the shadow map - RenderPass::RenderFlags renderPassFlags{}; - if (view.isFrontFaceWindingInverted()) { - renderPassFlags |= RenderPass::HAS_INVERSE_FRONT_FACES; - } - - bool const canUseDepthClamp = - !view.hasVSM() && - mIsDepthClampSupported && - engine.debug.shadowmap.depth_clamp; - - if (canUseDepthClamp) { - renderPassFlags |= RenderPass::HAS_DEPTH_CLAMP; - } - RenderPass const pass = passBuilder - .renderFlags(renderPassFlags) .camera(cameraInfo) .visibilityMask(entry.visibilityMask) .geometry(scene->getRenderableData(), entry.range) @@ -652,14 +637,8 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng cameraInfo.zf = -nearFarPlanes[i + 1]; updateNearFarPlanes(&cameraInfo.cullingProjection, cameraInfo.zn, cameraInfo.zf); - bool const canUseDepthClamp = - !view.hasVSM() && - mIsDepthClampSupported && - engine.debug.shadowmap.depth_clamp; - auto shaderParameters = shadowMap.updateDirectional(engine, - lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, - canUseDepthClamp); + lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, USE_DEPTH_CLAMP); if (shadowMap.hasVisibleShadows()) { const size_t shadowIndex = shadowMap.getShadowIndex(); diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 0d4b68324d..a823c1e4c1 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -232,7 +232,6 @@ private: ShadowMapCacheContainer mShadowMapCache; uint32_t mDirectionalShadowMapCount = 0; uint32_t mSpotShadowMapCount = 0; - bool const mIsDepthClampSupported; bool mInitialized = false; ShadowMap& getShadowMap(size_t index) noexcept { diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 27573fe66a..35abe8d947 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -590,6 +590,9 @@ void FRenderableManager::create( // full size of the UBO. instances.handle = driver.createBufferObject(sizeof(PerRenderableUib), BufferObjectBinding::UNIFORM, backend::BufferUsage::DYNAMIC); + if (auto name = instances.buffer->getName(); !name.empty()) { + driver.setDebugTag(instances.handle.getId(), std::move(name)); + } } const uint32_t boneCount = builder->mSkinningBoneCount; diff --git a/filament/src/details/BufferObject.cpp b/filament/src/details/BufferObject.cpp index 04a68223ba..a462e42a42 100644 --- a/filament/src/details/BufferObject.cpp +++ b/filament/src/details/BufferObject.cpp @@ -20,6 +20,8 @@ #include "FilamentAPI-impl.h" +#include + namespace filament { struct BufferObject::BuilderDetails { @@ -56,6 +58,9 @@ FBufferObject::FBufferObject(FEngine& engine, const BufferObject::Builder& build FEngine::DriverApi& driver = engine.getDriverApi(); mHandle = driver.createBufferObject(builder->mByteCount, builder->mBindingType, backend::BufferUsage::STATIC); + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(mHandle.getId(), std::move(name)); + } } void FBufferObject::terminate(FEngine& engine) { diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index ae2e24c608..c5c8567c88 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -617,7 +617,6 @@ public: bool focus_shadowcasters = true; bool visualize_cascades = false; bool disable_light_frustum_align = false; - bool depth_clamp = true; float dzn = -1.0f; float dzf = 1.0f; float display_shadow_texture_scale = 0.25f; diff --git a/filament/src/details/IndexBuffer.cpp b/filament/src/details/IndexBuffer.cpp index 66fc5d2f58..ae881de358 100644 --- a/filament/src/details/IndexBuffer.cpp +++ b/filament/src/details/IndexBuffer.cpp @@ -20,6 +20,8 @@ #include "FilamentAPI-impl.h" +#include + namespace filament { struct IndexBuffer::BuilderDetails { @@ -58,6 +60,9 @@ FIndexBuffer::FIndexBuffer(FEngine& engine, const IndexBuffer::Builder& builder) (backend::ElementType)builder->mIndexType, uint32_t(builder->mIndexCount), backend::BufferUsage::STATIC); + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(mHandle.getId(), std::move(name)); + } } void FIndexBuffer::terminate(FEngine& engine) { diff --git a/filament/src/details/InstanceBuffer.cpp b/filament/src/details/InstanceBuffer.cpp index af22554d0f..89fdd0e5d9 100644 --- a/filament/src/details/InstanceBuffer.cpp +++ b/filament/src/details/InstanceBuffer.cpp @@ -61,7 +61,8 @@ InstanceBuffer* InstanceBuffer::Builder::build(Engine& engine) { // ------------------------------------------------------------------------------------------------ -FInstanceBuffer::FInstanceBuffer(FEngine& engine, const Builder& builder) { +FInstanceBuffer::FInstanceBuffer(FEngine& engine, const Builder& builder) + : mName(builder.getName()) { mInstanceCount = builder->mInstanceCount; mLocalTransforms.reserve(mInstanceCount); diff --git a/filament/src/details/InstanceBuffer.h b/filament/src/details/InstanceBuffer.h index 2d25f7833e..56bac500c2 100644 --- a/filament/src/details/InstanceBuffer.h +++ b/filament/src/details/InstanceBuffer.h @@ -25,6 +25,7 @@ #include +#include #include namespace filament { @@ -46,10 +47,13 @@ public: void prepare(FEngine& engine, math::mat4f rootTransform, const PerRenderableData& ubo, backend::Handle handle); + utils::CString const& getName() const noexcept { return mName; } + private: friend class RenderableManager; utils::FixedCapacityVector mLocalTransforms; + utils::CString mName; size_t mInstanceCount; }; diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 8c76ff6852..407b435d4b 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -610,6 +610,7 @@ Program FMaterial::getProgramWithVariants( void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept { auto program = mEngine.getDriverApi().createProgram(std::move(p)); + mEngine.getDriverApi().setDebugTag(program.getId(), mName); assert_invariant(program); mCachedPrograms[variant.key] = program; } diff --git a/filament/src/details/MaterialInstance.cpp b/filament/src/details/MaterialInstance.cpp index c8726738a2..04c5fb0519 100644 --- a/filament/src/details/MaterialInstance.cpp +++ b/filament/src/details/MaterialInstance.cpp @@ -72,6 +72,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material) mUniforms = UniformBuffer(material->getUniformInterfaceBlock().getSize()); mUbHandle = driver.createBufferObject(mUniforms.getSize(), BufferObjectBinding::UNIFORM, backend::BufferUsage::STATIC); + driver.setDebugTag(mUbHandle.getId(), material->getName()); } // set the UBO, always descriptor 0 @@ -136,6 +137,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, mUniforms.setUniforms(other->getUniformBuffer()); mUbHandle = driver.createBufferObject(mUniforms.getSize(), BufferObjectBinding::UNIFORM, backend::BufferUsage::DYNAMIC); + driver.setDebugTag(mUbHandle.getId(), material->getName()); } // set the UBO, always descriptor 0 diff --git a/filament/src/details/MorphTargetBuffer.cpp b/filament/src/details/MorphTargetBuffer.cpp index 71aa13ab7e..f7c9444e04 100644 --- a/filament/src/details/MorphTargetBuffer.cpp +++ b/filament/src/details/MorphTargetBuffer.cpp @@ -25,6 +25,8 @@ #include #include +#include + namespace filament { using namespace backend; @@ -123,6 +125,11 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder) getHeight(mVertexCount), mCount, TextureUsage::DEFAULT); + + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(mPbHandle.getId(), name); + driver.setDebugTag(mTbHandle.getId(), std::move(name)); + } } void FMorphTargetBuffer::terminate(FEngine& engine) { diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 9254a76888..ff307a8f3b 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -656,16 +656,16 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { // on qualcomm hardware -- we might need a backend dependent toggle at some point const PostProcessManager::ColorGradingConfig colorGradingConfig{ .asSubpass = - hasColorGrading && msaaSampleCount <= 1 && - !bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled && driver.isFrameBufferFetchSupported() && + hasColorGrading && + !bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled && !engine.debug.renderer.disable_subpasses, .customResolve = - msaaOptions.customResolve && msaaSampleCount > 1 && - hasColorGrading && driver.isFrameBufferFetchMultiSampleSupported() && + msaaOptions.customResolve && + hasColorGrading && !engine.debug.renderer.disable_subpasses, .translucent = needsAlphaChannel, .fxaa = hasFXAA, @@ -674,6 +674,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { TextureFormat::RGBA8 : getLdrFormat(needsAlphaChannel) }; + // by construction (msaaSampleCount) both asSubpass and customResolve can't be true + assert_invariant(colorGradingConfig.asSubpass + colorGradingConfig.customResolve < 2); + // whether we're scaled at all bool scaled = any(notEqual(scale, float2(1.0f))); @@ -696,13 +699,12 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { CameraInfo cameraInfo = view.computeCameraInfo(engine); - // when colorgrading-as-subpass is active, we know that many other effects are disabled - // such as dof, bloom. Moreover, if fxaa and scaling are not enabled, we're essentially in - // a very fast rendering path -- in this case, we would need an extra blit to "resolve" the - // buffer padding (because there are no other pass that can do it as a side effect). - // In this case, it is better to skip the padding, which won't be helping much. - const bool noBufferPadding = (colorGradingConfig.asSubpass && !hasFXAA && !scaled) - || engine.debug.renderer.disable_buffer_padding; + // If fxaa and scaling are not enabled, we're essentially in a very fast rendering path -- in + // this case, we would need an extra blit to "resolve" the buffer padding (because there are no + // other pass that can do it as a side effect). In this case, it is better to skip the padding, + // which won't be helping much. + const bool noBufferPadding + = (!hasFXAA && !scaled) || engine.debug.renderer.disable_buffer_padding; // guardBand must be a multiple of 16 to guarantee the same exact rendering up to 4 mip levels. float const guardBand = guardBandOptions.enabled ? 16.0f : 0.0f; @@ -948,7 +950,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { .scale = aoOptions.resolution, .picking = view.hasPicking() }); - blackboard["structure"] = structure; const auto picking = picking_; @@ -1003,7 +1004,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { ssReflectionsOptions.enabled ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F, view.getCameraUser().getFieldOfView(Camera::Fov::VERTICAL), config.scale); config.ssrLodOffset = ssrConfig.lodOffset; - blackboard["ssr"] = ssrConfig.ssr; // -------------------------------------------------------------------------------------------- // screen-space reflections pass @@ -1108,24 +1108,39 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { ); // the color pass itself + color-grading as subpass if needed - auto colorPassOutput = RendererUtils::colorPass(fg, "Color Pass", mEngine, view, + auto colorPassOutput = RendererUtils::colorPass(fg, "Color Pass", mEngine, view, { + .shadows = blackboard.get("shadows"), + .ssao = blackboard.get("ssao"), + .ssr = ssrConfig.ssr, + .structure = structure + }, colorBufferDesc, config, colorGradingConfigForColor, pass.getExecutor()); if (view.isScreenSpaceRefractionEnabled() && !pass.empty()) { - // this cancels the colorPass() call above if refraction is active. - // the color pass + refraction + color-grading as subpass if needed - const auto [output, enabled] = RendererUtils::refractionPass(fg, mEngine, view, + // This cancels the colorPass() call above if refraction is active. + // The color pass + refraction + color-grading as subpass if needed + auto const output = RendererUtils::refractionPass(fg, mEngine, view, { + .shadows = blackboard.get("shadows"), + .ssao = blackboard.get("ssao"), + .ssr = ssrConfig.ssr, + .structure = structure + }, config, ssrConfig, colorGradingConfigForColor, pass); - colorPassOutput = output; - hasScreenSpaceRefraction = enabled; + + hasScreenSpaceRefraction = output.has_value(); + if (hasScreenSpaceRefraction) { + colorPassOutput = output.value(); + } } if (colorGradingConfig.customResolve) { + assert_invariant(fg.getDescriptor(colorPassOutput.linearColor).samples <= 1); // TODO: we have to "uncompress" (i.e. detonemap) the color buffer here because it's used // by many other passes (Bloom, TAA, DoF, etc...). We could make this more // efficient by using ARM_shader_framebuffer_fetch. We use a load/store (i.e. // subpass) here because it's more convenient. - colorPassOutput = ppm.customResolveUncompressPass(fg, colorPassOutput); + colorPassOutput.linearColor = + ppm.customResolveUncompressPass(fg, colorPassOutput.linearColor); } // export the color buffer if screen-space reflections are enabled @@ -1141,7 +1156,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { // The "output" of this pass is going to be used during the next frame as // an "import". builder.sideEffect(); - data.history = builder.sample(colorPassOutput); // FIXME: an access must be declared for detach(), why? + + // we can't use colorPassOutput here because it could be tonemapped + data.history = builder.sample(colorPassOutput.linearColor); // FIXME: an access must be declared for detach(), why? }, [&view, projection](FrameGraphResources const& resources, auto const& data, backend::DriverApi&) { auto& history = view.getFrameHistory(); @@ -1151,14 +1168,20 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { }); } - FrameGraphId input = colorPassOutput; + // this is the output of the color pass / input to post processing, + // this is only used later for comparing it with the output after post-processing + FrameGraphId const postProcessInput = colorGradingConfig.asSubpass ? + colorPassOutput.tonemappedColor : + colorPassOutput.linearColor; + + // input can change below + FrameGraphId input = postProcessInput; // Resolve depth -- which might be needed because of TAA or DoF. This pass will be culled // if the depth is not used below or if the depth is not MS (e.g. it could have been // auto-resolved). // In practice, this is used on Vulkan and older Metal devices. - auto depth = blackboard.get("depth"); - depth = ppm.resolve(fg, "Resolved Depth Buffer", depth, { .levels = 1 }); + auto depth = ppm.resolve(fg, "Resolved Depth Buffer", colorPassOutput.depth, { .levels = 1 }); // Debug: CSM visualisation if (UTILS_UNLIKELY(engine.debug.shadowmap.visualize_cascades && @@ -1274,7 +1297,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { // The intermediate buffer is accomplished with a "fake" opaqueBlit (i.e. blit) operation. const bool outputIsSwapChain = - (input == colorPassOutput) && (viewRenderTarget == mRenderTargetHandle); + (input == postProcessInput) && (viewRenderTarget == mRenderTargetHandle); if (mightNeedFinalBlit) { if (blendModeTranslucent || xvp != svp || diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 5970d56c94..0c5759323a 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -25,8 +25,9 @@ #include #include -#include +#include +#include #include #include @@ -81,6 +82,11 @@ FSkinningBuffer::FSkinningBuffer(FEngine& engine, const Builder& builder) BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC); + if (auto name = builder.getName(); !name.empty()) { + // TODO: We should also tag the texture created inside createIndicesAndWeightsHandle. + driver.setDebugTag(mHandle.getId(), std::move(name)); + } + if (builder->mInitialize) { // initialize the bones to identity (before rounding up) auto* out = driver.allocatePod(mBoneCount); diff --git a/filament/src/details/Stream.cpp b/filament/src/details/Stream.cpp index 317113ace0..c60bcf8bef 100644 --- a/filament/src/details/Stream.cpp +++ b/filament/src/details/Stream.cpp @@ -23,10 +23,10 @@ #include +#include #include #include - namespace filament { using namespace backend; @@ -80,6 +80,10 @@ FStream::FStream(FEngine& engine, const Builder& builder) noexcept } else { mStreamHandle = engine.getDriverApi().createStreamAcquired(); } + + if (auto name = builder.getName(); !name.empty()) { + engine.getDriverApi().setDebugTag(mStreamHandle.getId(), std::move(name)); + } } void FStream::terminate(FEngine& engine) noexcept { diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index e9cd835955..c1e574c260 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -252,7 +252,12 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) { mHandle = driver.importTexture(builder->mImportedId, mTarget, mLevelCount, mFormat, mSampleCount, mWidth, mHeight, mDepth, mUsage); } + mHandleForSampling = mHandle; + + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(mHandle.getId(), std::move(name)); + } } // frees driver resources, object becomes invalid diff --git a/filament/src/details/VertexBuffer.cpp b/filament/src/details/VertexBuffer.cpp index 6269bc5ed7..8aabcf4fc7 100644 --- a/filament/src/details/VertexBuffer.cpp +++ b/filament/src/details/VertexBuffer.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -259,7 +260,9 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build mBufferCount, mDeclaredAttributes.count(), mAttributes); mHandle = driver.createVertexBuffer(mVertexCount, mVertexBufferInfoHandle); - + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(mHandle.getId(), name); + } // calculate buffer sizes size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {}; @@ -287,6 +290,9 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build if (!mBufferObjects[i]) { BufferObjectHandle bo = driver.createBufferObject(bufferSizes[i], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(bo.getId(), name); + } driver.setVertexBufferObject(mHandle, i, bo); mBufferObjects[i] = bo; } @@ -303,6 +309,9 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build if (!mBufferObjects[i]) { BufferObjectHandle const bo = driver.createBufferObject(bufferSizes[i], backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC); + if (auto name = builder.getName(); !name.empty()) { + driver.setDebugTag(bo.getId(), name); + } driver.setVertexBufferObject(mHandle, i, bo); mBufferObjects[i] = bo; } diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 8ec4c8d8cc..1e87d19b7e 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.54.0" + spec.version = "1.54.1" 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.54.0/filament-v1.54.0-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.54.1/filament-v1.54.1-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/libs/gltfio/src/MaterialProvider.cpp b/libs/gltfio/src/MaterialProvider.cpp index 7e7fa6d947..7de9234152 100644 --- a/libs/gltfio/src/MaterialProvider.cpp +++ b/libs/gltfio/src/MaterialProvider.cpp @@ -56,7 +56,13 @@ bool operator==(const MaterialKey& k1, const MaterialKey& k2) { (k1.volumeThicknessUV == k2.volumeThicknessUV) && (k1.hasSheen == k2.hasSheen) && (k1.hasIOR == k2.hasIOR) && - (k1.hasVolume == k2.hasVolume); + (k1.hasVolume == k2.hasVolume) && + (k1.hasSpecular == k2.hasSpecular) && + (k1.hasSpecularTexture == k2.hasSpecularTexture) && + (k1.hasSpecularColorTexture == k2.hasSpecularColorTexture) && + (k1.specularTextureUV == k2.specularTextureUV) && + (k1.specularColorTextureUV == k2.specularColorTextureUV) + ; } // Filament supports up to 2 UV sets. glTF has arbitrary texcoord set indices, but it allows diff --git a/libs/gltfio/src/UbershaderProvider.cpp b/libs/gltfio/src/UbershaderProvider.cpp index 64451aa363..d70c5ab695 100644 --- a/libs/gltfio/src/UbershaderProvider.cpp +++ b/libs/gltfio/src/UbershaderProvider.cpp @@ -259,6 +259,24 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config mi->setParameter("occlusionUvMatrix", identity); mi->setParameter("emissiveUvMatrix", identity); + // set to -1 all possibly optional parameters + for (auto const* param : { + "clearCoatIndex", + "clearCoatRoughnessIndex", + "clearCoatNormalIndex", + "sheenColorIndex", + "sheenRoughnessIndex", + "volumeThicknessUvMatrix", + "volumeThicknessIndex", + "transmissionIndex", + "specularIndex", + "specularColorIndex", + }) { + if (material->hasParameter(param)) { + mi->setParameter(param, -1); + } + } + if (config->hasClearCoat) { mi->setParameter("clearCoatIndex", getUvIndex(config->clearCoatUV, config->hasClearCoatTexture)); @@ -340,10 +358,10 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config mi->setParameter("sheenRoughnessMap", mDummyTexture, sampler); } - if (mi->getMaterial()->hasParameter("ior")) { + if (material->hasParameter("ior")) { mi->setParameter("ior", 1.5f); } - if (mi->getMaterial()->hasParameter("reflectance")) { + if (material->hasParameter("reflectance")) { mi->setParameter("reflectance", 0.5f); } @@ -355,6 +373,14 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config mi->setParameter("specularColorMap", mDummyTexture, sampler); } + if (material->hasParameter("specularColorFactor")) { + mi->setParameter("specularColorFactor", float3(1.0f)); + } + + if (material->hasParameter("specularStrength")) { + mi->setParameter("specularStrength", 1.0f); + } + return mi; } diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index e3dc4363a3..6206c0c9a4 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -905,8 +905,6 @@ int main(int argc, char** argv) { debug.getPropertyAddress("d.shadowmap.focus_shadowcasters")); ImGui::Checkbox("Disable light frustum alignment", debug.getPropertyAddress("d.shadowmap.disable_light_frustum_align")); - ImGui::Checkbox("Depth clamp", - debug.getPropertyAddress("d.shadowmap.depth_clamp")); bool debugDirectionalShadowmap; if (debug.getProperty("d.shadowmap.debug_directional_shadowmap", diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 60f36d09e9..21ca5f2f83 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.54.0", + "version": "1.54.1", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",