diff --git a/README.md b/README.md index cbfa132634b9..0907d9794c27 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.56.1' + implementation 'com.google.android.filament:filament-android:1.56.2' } ``` @@ -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.1' +pod 'Filament', '~> 1.56.2' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 42e68e62acc3..9f82faac507b 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.56.2 + +- vk: fix stage pool gc logic + ## v1.56.1 ## v1.56.0 diff --git a/android/gradle.properties b/android/gradle.properties index c657979b6c3f..a478149a0ea0 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.56.1 +VERSION_NAME=1.56.2 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 4fe1c6040174..82e336215dd3 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -308,6 +308,11 @@ if (FILAMENT_ENABLE_MULTIVIEW) add_definitions(-DFILAMENT_ENABLE_MULTIVIEW) endif() +# Whether to force the profiling mode. +if (FILAMENT_FORCE_PROFILING_MODE) + add_definitions(-DFILAMENT_FORCE_PROFILING_MODE) +endif() + # ================================================================================================== # Definitions # ================================================================================================== diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 0a07c82836de..c44643a3f566 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -221,9 +221,6 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/VulkanSwapChain.h src/vulkan/VulkanReadPixels.cpp src/vulkan/VulkanReadPixels.h - src/vulkan/VulkanResourceAllocator.h - src/vulkan/VulkanResources.cpp - src/vulkan/VulkanResources.h src/vulkan/VulkanTexture.cpp src/vulkan/VulkanTexture.h src/vulkan/VulkanUtility.cpp @@ -378,10 +375,6 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS if (LINUX AND FILAMENT_SUPPORTS_OSMESA) set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL) - set(OSMESA_LINKER_FLAGS - -Wl,-L${FILAMENT_OSMESA_PATH}/lib/x86_64-linux-gnu/ - -lOSMesa - ) endif() if (MSVC) diff --git a/filament/backend/include/backend/platforms/PlatformOSMesa.h b/filament/backend/include/backend/platforms/PlatformOSMesa.h index bcb82195a4c1..a1a72fc6f774 100644 --- a/filament/backend/include/backend/platforms/PlatformOSMesa.h +++ b/filament/backend/include/backend/platforms/PlatformOSMesa.h @@ -21,7 +21,7 @@ #include "bluegl/BlueGL.h" -#include "osmesa.h" +#include #include #include @@ -56,6 +56,7 @@ class PlatformOSMesa : public OpenGLPlatform { private: OSMesaContext mContext; + void* mOsMesaApi = nullptr; }; } // namespace filament::backend diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 26045518199c..bee3ba883553 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -797,9 +797,20 @@ } void MetalDriver::destroyProgram(Handle ph) { - if (ph) { - destruct_handle(ph); + if (UTILS_UNLIKELY(!ph)) { + return; + } + // Remove any cached pipeline states that refer to these programs. + auto* metalProgram = handle_cast(ph); + const auto& functions = metalProgram->getFunctionsIfPresent(); + if (UTILS_LIKELY(functions.isRaster())) { // only raster pipelines are cached + const auto& raster = functions.getRasterFunctions(); + mContext->pipelineStateCache.removeIf([&](const MetalPipelineState& state) { + const auto& [fragment, vertex] = raster; + return state.fragmentFunction == fragment || state.vertexFunction == vertex; + }); } + destruct_handle(ph); } void MetalDriver::destroyTexture(Handle th) { diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index 0c02b213edbc..484e1dba490a 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -202,6 +202,7 @@ class MetalProgram : public HwProgram { MetalProgram(MetalContext& context, Program&& program) noexcept; const MetalShaderCompiler::MetalFunctionBundle& getFunctions(); + const MetalShaderCompiler::MetalFunctionBundle& getFunctionsIfPresent() const; private: void initialize(); @@ -437,7 +438,7 @@ struct MetalTimerQuery : public HwTimerQuery { struct Status { std::atomic available {false}; - uint64_t elapsed {0}; // only valid if available is true + std::atomic elapsed {0}; // only valid if available is true }; std::shared_ptr status; diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index 443d4435a915..60cf484c86ea 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -495,6 +495,10 @@ static void func(void* user) { return mFunctionBundle; } +const MetalShaderCompiler::MetalFunctionBundle& MetalProgram::getFunctionsIfPresent() const { + return mFunctionBundle; +} + void MetalProgram::initialize() { if (!mToken) { return; diff --git a/filament/backend/src/metal/MetalShaderCompiler.h b/filament/backend/src/metal/MetalShaderCompiler.h index f0b827ad6ac5..dfb29f47b083 100644 --- a/filament/backend/src/metal/MetalShaderCompiler.h +++ b/filament/backend/src/metal/MetalShaderCompiler.h @@ -83,6 +83,10 @@ class MetalShaderCompiler { return std::get(mPrograms); } + bool isRaster() const { return std::holds_alternative(mPrograms); } + + bool isCompute() const { return std::holds_alternative(mPrograms); } + static MetalFunctionBundle none() { return MetalFunctionBundle(None{}); } diff --git a/filament/backend/src/metal/MetalState.h b/filament/backend/src/metal/MetalState.h index 92d5a3319c20..a9e9e76fff4f 100644 --- a/filament/backend/src/metal/MetalState.h +++ b/filament/backend/src/metal/MetalState.h @@ -28,7 +28,9 @@ #include #include + #include +#include namespace filament { namespace backend { @@ -160,6 +162,8 @@ template> class StateCache { + using MapType = tsl::robin_map; + public: StateCache() = default; @@ -169,6 +173,18 @@ class StateCache { void setDevice(id device) noexcept { mDevice = device; } + void removeIf(utils::Invocable fn) noexcept { + typename MapType::const_iterator it = mStateCache.begin(); + while (it != mStateCache.end()) { + const auto& [key, _] = *it; + if (UTILS_UNLIKELY(fn(key))) { + it = mStateCache.erase(it); + } else { + ++it; + } + } + } + MetalType getOrCreateState(const StateType& state) noexcept { assert_invariant(mDevice); @@ -196,7 +212,7 @@ class StateCache { StateCreator creator; id mDevice = nil; - tsl::robin_map mStateCache; + MapType mStateCache; }; diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index e5d535f036f3..79580fc7c46e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -106,17 +106,29 @@ // set to the desired debug level (for internal debugging [Default: None]) #define DEBUG_MARKER_LEVEL DEBUG_MARKER_NONE +// Override the debug markers if we are forcing profiling mode +#if defined(FILAMENT_FORCE_PROFILING_MODE) +# undef DEBUG_GROUP_MARKER_LEVEL +# undef DEBUG_MARKER_LEVEL + +# define DEBUG_GROUP_MARKER_LEVEL DEBUG_GROUP_MARKER_NONE +# define DEBUG_MARKER_LEVEL DEBUG_MARKER_PROFILE +#endif + #if DEBUG_MARKER_LEVEL == DEBUG_MARKER_PROFILE # define DEBUG_MARKER() # define PROFILE_MARKER(marker) PROFILE_SCOPE(marker); # if DEBUG_GROUP_MARKER_LEVEL != DEBUG_GROUP_MARKER_NONE -# error PROFILING is exclusive; group markers must be disabled. +# error PROFILING is exclusive; group markers must be disabled. +# endif +# ifndef NDEBUG +# error PROFILING is meaningless in DEBUG mode. # endif #elif DEBUG_MARKER_LEVEL > DEBUG_MARKER_NONE # define DEBUG_MARKER() DebugMarker _debug_marker(*this, __func__); # define PROFILE_MARKER(marker) DEBUG_MARKER() # if DEBUG_MARKER_LEVEL & DEBUG_MARKER_PROFILE -# error PROFILING is exclusive; all other debug features must be disabled. +# error PROFILING is exclusive; all other debug features must be disabled. # endif #else # define DEBUG_MARKER() @@ -1670,7 +1682,7 @@ void OpenGLDriver::createSwapChainR(Handle sch, void* nativeWindow, // See if we need the emulated rec709 output conversion if (UTILS_UNLIKELY(mContext.isES2())) { - sc->rec709 = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE && + sc->rec709 = ((flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) && !mPlatform.isSRGBSwapChainSupported()); } } diff --git a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp index 9a34577dc1cc..fdeccfe110f0 100644 --- a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp +++ b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp @@ -19,6 +19,7 @@ #include #include +#include #include namespace filament::backend { @@ -41,13 +42,56 @@ struct OSMesaSwapchain { std::unique_ptr buffer; }; -} // anonymous namespace +struct OSMesaAPI { +private: + using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext); + using DestroyContextFunc = GLboolean (*)(OSMesaContext); + using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type, + GLsizei width, GLsizei height); + using GetProcAddressFunc = OSMESAproc (*)(const char* funcName); + +public: + CreateContextFunc OSMesaCreateContext; + DestroyContextFunc OSMesaDestroyContext; + MakeCurrentFunc OSMesaMakeCurrent; + GetProcAddressFunc OSMesaGetProcAddress; + + OSMesaAPI() { + constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + for (char const* libName: libraryNames) { + mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW); + if (mLib) { + break; + } + } + FILAMENT_CHECK_PRECONDITION(mLib) + << "Unable to dlopen libOSMesa to create a software GL context"; + + OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress"); + + OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext"); + OSMesaDestroyContext = + (DestroyContextFunc) OSMesaGetProcAddress("OSMesaDestroyContext"); + OSMesaMakeCurrent = (MakeCurrentFunc) OSMesaGetProcAddress("OSMesaMakeCurrent"); + } + + ~OSMesaAPI() { + dlclose(mLib); + } +private: + void* mLib = nullptr; +}; + +}// anonymous namespace Driver* PlatformOSMesa::createDriver(void* const sharedGLContext, const DriverConfig& driverConfig) noexcept { + OSMesaAPI* api = new OSMesaAPI(); + mOsMesaApi = api; + FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr) << "shared GL context is not supported with PlatformOSMesa"; - mContext = OSMesaCreateContext(GL_RGBA, NULL); + mContext = api->OSMesaCreateContext(GL_RGBA, NULL); // We need to do a no-op makecurrent here so that the context will be in a correct state before // any GL calls. @@ -62,7 +106,11 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext, } void PlatformOSMesa::terminate() noexcept { - OSMesaDestroyContext(mContext); + OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi; + api->OSMesaDestroyContext(mContext); + delete api; + mOsMesaApi = nullptr; + bluegl::unbind(); } @@ -84,11 +132,12 @@ void PlatformOSMesa::destroySwapChain(Platform::SwapChain* swapChain) noexcept { bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept { + OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi; OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain; - auto result = OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(), BACKING_GL_TYPE, - impl->width, impl->height); - FILAMENT_CHECK_POSTCONDITION(result) << "OSMesaMakeCurrent failed!"; + auto result = api->OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(), + BACKING_GL_TYPE, impl->width, impl->height); + FILAMENT_CHECK_POSTCONDITION(result == GL_TRUE) << "OSMesaMakeCurrent failed!"; return true; } diff --git a/filament/backend/src/vulkan/VulkanAsyncHandles.cpp b/filament/backend/src/vulkan/VulkanAsyncHandles.cpp index 46d6ed38bf6d..82963b05c4d9 100644 --- a/filament/backend/src/vulkan/VulkanAsyncHandles.cpp +++ b/filament/backend/src/vulkan/VulkanAsyncHandles.cpp @@ -19,8 +19,7 @@ namespace filament::backend { VulkanTimerQuery::VulkanTimerQuery(std::tuple indices) - : VulkanThreadSafeResource(VulkanResourceType::TIMER_QUERY), - mStartingQueryIndex(std::get<0>(indices)), + : mStartingQueryIndex(std::get<0>(indices)), mStoppingQueryIndex(std::get<1>(indices)) {} void VulkanTimerQuery::setFence(std::shared_ptr fence) noexcept { diff --git a/filament/backend/src/vulkan/VulkanAsyncHandles.h b/filament/backend/src/vulkan/VulkanAsyncHandles.h index 4e7920fd4dae..eb626871ae36 100644 --- a/filament/backend/src/vulkan/VulkanAsyncHandles.h +++ b/filament/backend/src/vulkan/VulkanAsyncHandles.h @@ -21,7 +21,7 @@ #include "DriverBase.h" -#include "VulkanResources.h" +#include "vulkan/memory/Resource.h" #include #include @@ -47,17 +47,12 @@ struct VulkanCmdFence { std::atomic status; }; -struct VulkanFence : public HwFence, VulkanResource { - VulkanFence() : VulkanResource(VulkanResourceType::FENCE) {} - - explicit VulkanFence(std::shared_ptr fence) - : VulkanResource(VulkanResourceType::FENCE), - fence(fence) {} - +struct VulkanFence : public HwFence, fvkmemory::ThreadSafeResource { + VulkanFence() {} std::shared_ptr fence; }; -struct VulkanTimerQuery : public HwTimerQuery, VulkanThreadSafeResource { +struct VulkanTimerQuery : public HwTimerQuery, fvkmemory::ThreadSafeResource { explicit VulkanTimerQuery(std::tuple indices); ~VulkanTimerQuery(); diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp index db68b94b58b1..bcb786e63aed 100644 --- a/filament/backend/src/vulkan/VulkanBlitter.cpp +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -126,8 +126,7 @@ struct BlitterUniforms { }// anonymous namespace VulkanBlitter::VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept - : mPhysicalDevice(physicalDevice), - mCommands(commands) {} + : mPhysicalDevice(physicalDevice), mCommands(commands) {} void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) { @@ -151,7 +150,8 @@ void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) { } #endif - VulkanCommandBuffer& commands = mCommands->get(); + VulkanCommandBuffer& commands = dst.texture->getIsProtected() ? + mCommands->getProtected() : mCommands->get(); commands.acquire(src.texture); commands.acquire(dst.texture); resolveFast(&commands, aspect, src, dst); @@ -176,7 +176,8 @@ void VulkanBlitter::blit(VkFilter filter, #endif // src and dst should have the same aspect here VkImageAspectFlags const aspect = src.texture->getImageAspect(); - VulkanCommandBuffer& commands = mCommands->get(); + VulkanCommandBuffer& commands = dst.texture->getIsProtected() ? + mCommands->getProtected() : mCommands->get(); commands.acquire(src.texture); commands.acquire(dst.texture); blitFast(&commands, aspect, filter, src, dst, srcRectPair, dstRectPair); diff --git a/filament/backend/src/vulkan/VulkanCommands.cpp b/filament/backend/src/vulkan/VulkanCommands.cpp index c3548d5cbbc8..e531f3433f67 100644 --- a/filament/backend/src/vulkan/VulkanCommands.cpp +++ b/filament/backend/src/vulkan/VulkanCommands.cpp @@ -58,66 +58,41 @@ VkCommandBuffer createCommandBuffer(VkDevice device, VkCommandPool pool) { #if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) void VulkanGroupMarkers::push(std::string const& marker, Timestamp start) noexcept { - mMarkers.push_back(marker); - -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - mTimestamps.push_back(start.time_since_epoch().count() > 0.0 - ? start - : std::chrono::high_resolution_clock::now()); -#endif + mMarkers.push_back({marker, + start.time_since_epoch().count() > 0.0 + ? start + : std::chrono::high_resolution_clock::now()}); } std::pair VulkanGroupMarkers::pop() noexcept { - auto const marker = mMarkers.back(); + auto ret = mMarkers.back(); mMarkers.pop_back(); - -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - auto const timestamp = mTimestamps.back(); - mTimestamps.pop_back(); - return std::make_pair(marker, timestamp); -#else - return std::make_pair(marker, Timestamp{}); -#endif + return ret; } std::pair VulkanGroupMarkers::pop_bottom() noexcept { - auto const marker = mMarkers.front(); + auto ret = mMarkers.front(); mMarkers.pop_front(); - -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - auto const timestamp = mTimestamps.front(); - mTimestamps.pop_front(); - return std::make_pair(marker, timestamp); -#else - return std::make_pair(marker, Timestamp{}); -#endif + return ret; } -std::pair VulkanGroupMarkers::top() const { +std::pair const& VulkanGroupMarkers::top() const { assert_invariant(!empty()); - auto const marker = mMarkers.back(); -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - auto const topTimestamp = mTimestamps.front(); - return std::make_pair(marker, topTimestamp); -#else - return std::make_pair(marker, Timestamp{}); -#endif + return mMarkers.back(); } bool VulkanGroupMarkers::empty() const noexcept { return mMarkers.empty(); } - #endif // FVK_DEBUG_GROUP_MARKERS -VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext* context, VulkanResourceAllocator* allocator, - VkDevice device, VkQueue queue, VkCommandPool pool, bool isProtected) +VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext* context, VkDevice device, VkQueue queue, + VkCommandPool pool, bool isProtected) : mContext(context), mMarkerCount(0), isProtected(isProtected), mDevice(device), mQueue(queue), - mResourceManager(allocator), mBuffer(createCommandBuffer(device, pool)), mFenceStatus(std::make_shared(VK_INCOMPLETE)) { VkSemaphoreCreateInfo sci{.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; @@ -134,7 +109,7 @@ VulkanCommandBuffer::~VulkanCommandBuffer() { void VulkanCommandBuffer::reset() noexcept { mMarkerCount = 0; - mResourceManager.clear(); + mResources.clear(); mWaitSemaphores.clear(); // Internally we use the VK_INCOMPLETE status to mean "not yet submitted". When this fence @@ -257,8 +232,8 @@ VkSemaphore VulkanCommandBuffer::submit() { return mSubmission; } -CommandBufferPool::CommandBufferPool(VulkanContext* context, VulkanResourceAllocator* allocator, - VkDevice device, VkQueue queue, uint8_t queueFamilyIndex, bool isProtected) +CommandBufferPool::CommandBufferPool(VulkanContext* context, VkDevice device, VkQueue queue, + uint8_t queueFamilyIndex, bool isProtected) : mDevice(device), mRecording(INVALID) { VkCommandPoolCreateInfo createInfo = { @@ -271,8 +246,8 @@ CommandBufferPool::CommandBufferPool(VulkanContext* context, VulkanResourceAlloc vkCreateCommandPool(device, &createInfo, VKALLOC, &mPool); for (size_t i = 0; i < CAPACITY; ++i) { - mBuffers.emplace_back(std::make_unique(context, allocator, device, - queue, mPool, isProtected)); + mBuffers.emplace_back( + std::make_unique(context, device, queue, mPool, isProtected)); } } @@ -303,6 +278,19 @@ VulkanCommandBuffer& CommandBufferPool::getRecording() { auto& recording = *mBuffers[mRecording]; recording.begin(); + +#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) + if (mGroupMarkers) { + std::unique_ptr markers = std::make_unique(); + while (!mGroupMarkers->empty()) { + auto [marker, timestamp] = mGroupMarkers->pop_bottom(); + recording.pushMarker(marker.c_str()); + markers->push(marker, timestamp); + } + std::swap(mGroupMarkers, markers); + } +#endif + return recording; } @@ -357,29 +345,46 @@ void CommandBufferPool::waitFor(VkSemaphore previousAction) { recording->insertWait(previousAction); } -void CommandBufferPool::pushMarker(char const* marker) { +#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) +std::string CommandBufferPool::topMarker() const { + if (!mGroupMarkers || mGroupMarkers->empty()) { + return ""; + } + return std::get<0>(mGroupMarkers->top()); +} + +void CommandBufferPool::pushMarker(char const* marker, VulkanGroupMarkers::Timestamp timestamp) { + if (!mGroupMarkers) { + mGroupMarkers = std::make_unique(); + } + mGroupMarkers->push(marker, timestamp); getRecording().pushMarker(marker); } -void CommandBufferPool::popMarker() { - getRecording().popMarker(); +std::pair CommandBufferPool::popMarker() { + assert_invariant(mGroupMarkers && !mGroupMarkers->empty()); + auto ret = mGroupMarkers->pop(); + + // Note that if we're popping a marker while not recording, we would just pop the conceptual + // stack of marker (i.e. mGroupMarkers) and not carry out the pop on the command buffer. + if (isRecording()) { + getRecording().popMarker(); + } + return ret; } void CommandBufferPool::insertEvent(char const* marker) { getRecording().insertEvent(marker); } +#endif // FVK_DEBUG_GROUP_MARKERS VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex, - VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext* context, - VulkanResourceAllocator* allocator) + VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext* context) : mDevice(device), mProtectedQueue(protectedQueue), mProtectedQueueFamilyIndex(protectedQueueFamilyIndex), - mAllocator(allocator), mContext(context), - mPool(std::make_unique(context, allocator, device, queue, queueFamilyIndex, - false)) { -} + mPool(std::make_unique(context, device, queue, queueFamilyIndex, false)) {} void VulkanCommands::terminate() { mPool.reset(); @@ -395,14 +400,19 @@ VulkanCommandBuffer& VulkanCommands::getProtected() { assert_invariant(mProtectedQueue != VK_NULL_HANDLE); if (!mProtectedPool) { - mProtectedPool = std::make_unique(mContext, mAllocator, mDevice, - mProtectedQueue, mProtectedQueueFamilyIndex, true); + mProtectedPool = std::make_unique(mContext, mDevice, mProtectedQueue, + mProtectedQueueFamilyIndex, true); } auto& ret = mProtectedPool->getRecording(); return ret; } bool VulkanCommands::flush() { + // It's possible to call flush and wait at "terminate", in which case, we'll just return. + if (!mPool && !mProtectedPool) { + return false; + } + VkSemaphore dependency = mInjectedDependency; VkSemaphore lastSubmit = mLastSubmit; bool hasFlushed = false; @@ -434,6 +444,11 @@ bool VulkanCommands::flush() { } void VulkanCommands::wait() { + // It's possible to call flush and wait at "terminate", in which case, we'll just return. + if (!mPool && !mProtectedPool) { + return; + } + FVK_SYSTRACE_CONTEXT(); FVK_SYSTRACE_START("commands::wait"); @@ -465,47 +480,31 @@ void VulkanCommands::updateFences() { #if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp) { -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - // If the timestamp is not 0, then we are carrying over a marker across buffer submits. - // If it is 0, then this is a normal marker push and we should just print debug line as usual. - if (timestamp.time_since_epoch().count() == 0.0) { - FVK_LOGD << "----> " << str << utils::io::endl; - } -#endif - if (!mGroupMarkers) { - mGroupMarkers = std::make_unique(); - } - mGroupMarkers->push(str, timestamp); - - mPool->pushMarker(str); + mPool->pushMarker(str, timestamp); if (mProtectedPool) { - mProtectedPool->pushMarker(str); + mProtectedPool->pushMarker(str, timestamp); } +#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) + FVK_LOGD << "----> " << str << utils::io::endl; +#endif } void VulkanCommands::popGroupMarker() { - assert_invariant(mGroupMarkers); - if (!mGroupMarkers->empty()) { - VkCommandBuffer const cmdbuffer = get().buffer(); #if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - auto const [marker, startTime] = mGroupMarkers->pop(); - auto const endTime = std::chrono::high_resolution_clock::now(); - std::chrono::duration diff = endTime - startTime; - FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms" - << utils::io::endl; + auto ret = mPool->popMarker(); + auto const& marker = ret.first; + auto const& startTime = ret.second; + auto const endTime = std::chrono::high_resolution_clock::now(); + std::chrono::duration diff = endTime - startTime; + FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms" + << utils::io::endl; #else - mGroupMarkers->pop(); -#endif - mPool->popMarker(); - if (mProtectedPool) { - mProtectedPool->popMarker(); - } - } else if (mCarriedOverMarkers && !mCarriedOverMarkers->empty()) { - // It could be that pop is called between flush() and get() (new command buffer), in which - // case the marker is in "carried over" state, we'd just remove that. Since the - // mCarriedOverMarkers is in the opposite order, we pop the bottom instead of the top. - mCarriedOverMarkers->pop_bottom(); + mPool->popMarker(); +#endif // FVK_DEBUG_PRINT_GROUP_MARKERS + + if (mProtectedPool) { + mProtectedPool->popMarker(); } } @@ -517,10 +516,10 @@ void VulkanCommands::insertEventMarker(char const* str, uint32_t len) { } std::string VulkanCommands::getTopGroupMarker() const { - if (!mGroupMarkers || mGroupMarkers->empty()) { - return ""; + if (mProtectedPool) { + return mProtectedPool->topMarker(); } - return std::get<0>(mGroupMarkers->top()); + return mPool->topMarker(); } #endif // FVK_DEBUG_GROUP_MARKERS diff --git a/filament/backend/src/vulkan/VulkanCommands.h b/filament/backend/src/vulkan/VulkanCommands.h index 25b839ec49e3..2e331dfa4ada 100644 --- a/filament/backend/src/vulkan/VulkanCommands.h +++ b/filament/backend/src/vulkan/VulkanCommands.h @@ -23,8 +23,8 @@ #include "VulkanAsyncHandles.h" #include "VulkanConstants.h" -#include "VulkanResources.h" #include "VulkanUtility.h" +#include "vulkan/memory/ResourcePointer.h" #include #include @@ -39,6 +39,8 @@ namespace filament::backend { +using namespace fvkmemory; + struct VulkanContext; #if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) @@ -49,14 +51,11 @@ class VulkanGroupMarkers { void push(std::string const& marker, Timestamp start = {}) noexcept; std::pair pop() noexcept; std::pair pop_bottom() noexcept; - std::pair top() const; + std::pair const& top() const; bool empty() const noexcept; private: - std::list mMarkers; -#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS) - std::list mTimestamps; -#endif + std::list> mMarkers; }; #endif // FVK_DEBUG_GROUP_MARKERS @@ -65,7 +64,7 @@ class VulkanGroupMarkers { // DriverApi fence object and should not be destroyed until both the DriverApi object is freed and // we're done waiting on the most recent submission of the given command buffer. struct VulkanCommandBuffer { - VulkanCommandBuffer(VulkanContext* mContext, VulkanResourceAllocator* allocator, + VulkanCommandBuffer(VulkanContext* mContext, VkDevice device, VkQueue queue, VkCommandPool pool, bool isProtected); VulkanCommandBuffer(VulkanCommandBuffer const&) = delete; @@ -73,13 +72,10 @@ struct VulkanCommandBuffer { ~VulkanCommandBuffer(); - inline void acquire(VulkanResource* resource) { - mResourceManager.acquire(resource); + inline void acquire(fvkmemory::resource_ptr resource) { + mResources.push_back(resource); } - inline void acquire(VulkanAcquireOnlyResourceManager* srcResources) { - mResourceManager.acquireAll(srcResources); - } void reset() noexcept; inline void insertWait(VkSemaphore sem) { @@ -119,21 +115,20 @@ struct VulkanCommandBuffer { bool const isProtected; VkDevice mDevice; VkQueue mQueue; - VulkanAcquireOnlyResourceManager mResourceManager; CappedArray mWaitSemaphores; VkCommandBuffer mBuffer; VkSemaphore mSubmission; VkFence mFence; std::shared_ptr mFenceStatus; - + std::vector> mResources; }; struct CommandBufferPool { - using ActiveBuffers = utils::bitset32; + using ActiveBuffers = utils::bitset64; static constexpr int8_t INVALID = -1; - CommandBufferPool(VulkanContext* context, VulkanResourceAllocator* allocator, VkDevice device, - VkQueue queue, uint8_t queueFamilyIndex, bool isProtected); + CommandBufferPool(VulkanContext* context, VkDevice device, VkQueue queue, + uint8_t queueFamilyIndex, bool isProtected); ~CommandBufferPool(); VulkanCommandBuffer& getRecording(); @@ -142,12 +137,14 @@ struct CommandBufferPool { void update(); VkSemaphore flush(); void wait(); - void waitFor(VkSemaphore previousAction); - void pushMarker(char const* marker); - void popMarker(); +#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) + std::string topMarker() const; + void pushMarker(char const* marker, VulkanGroupMarkers::Timestamp timestamp); + std::pair popMarker(); void insertEvent(char const* marker); +#endif inline bool isRecording() const { return mRecording != INVALID; } @@ -155,12 +152,21 @@ struct CommandBufferPool { static constexpr int CAPACITY = FVK_MAX_COMMAND_BUFFERS; // int8 only goes up to 127, therefore capacity must be less than that. static_assert(CAPACITY < 128); + + // The number of bits in ActiveBuffers describe the usage of the buffers in the pool, so must be + // larger than the size of the pool. + static_assert(sizeof(ActiveBuffers) * 8 >= CAPACITY); + using BufferList = utils::FixedCapacityVector>; VkDevice mDevice; VkCommandPool mPool; ActiveBuffers mSubmitted; std::vector> mBuffers; int8_t mRecording; + +#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) + std::unique_ptr mGroupMarkers; +#endif }; // Manages a set of command buffers and semaphores, exposing an API that is significantly simpler @@ -189,8 +195,7 @@ struct CommandBufferPool { class VulkanCommands { public: VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex, - VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext* context, - VulkanResourceAllocator* allocator); + VkQueue protectedQueue, uint32_t protectedQueueFamilyIndex, VulkanContext* context); void terminate(); @@ -241,7 +246,6 @@ class VulkanCommands { VkQueue const mProtectedQueue; // For defered initialization if/when we need protected content uint32_t const mProtectedQueueFamilyIndex; - VulkanResourceAllocator* mAllocator; VulkanContext* mContext; std::unique_ptr mPool; @@ -249,11 +253,6 @@ class VulkanCommands { VkSemaphore mInjectedDependency = VK_NULL_HANDLE; VkSemaphore mLastSubmit = VK_NULL_HANDLE; - -#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS) - std::unique_ptr mGroupMarkers; - std::unique_ptr mCarriedOverMarkers; -#endif }; } // namespace filament::backend diff --git a/filament/backend/src/vulkan/VulkanConstants.h b/filament/backend/src/vulkan/VulkanConstants.h index c291a0c4f139..1a454d706967 100644 --- a/filament/backend/src/vulkan/VulkanConstants.h +++ b/filament/backend/src/vulkan/VulkanConstants.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2021 The Android Open Source Project * -* Licensed under the Apache License, Version 2.0 (the "License"); + * 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 * @@ -63,7 +63,7 @@ #define FVK_DEBUG_SHADER_MODULE 0x00000800 #define FVK_DEBUG_READ_PIXELS 0x00001000 #define FVK_DEBUG_PIPELINE_CACHE 0x00002000 -#define FVK_DEBUG_ALLOCATION 0x00004000 +#define FVK_DEBUG_STAGING_ALLOCATION 0x00004000 // Enable the debug utils extension if it is available. #define FVK_DEBUG_DEBUG_UTILS 0x00008000 @@ -98,6 +98,12 @@ #define FVK_DEBUG_FLAGS 0 #endif +// Override the debug flags if we are forcing profiling mode +#if defined(FILAMENT_FORCE_PROFILING_MODE) +#undef FVK_DEBUG_FLAGS +#define FVK_DEBUG_FLAGS (FVK_DEBUG_PROFILING) +#endif + #define FVK_ENABLED(flags) (((FVK_DEBUG_FLAGS) & (flags)) == (flags)) // Group marker only works only if validation or debug utils is enabled since it uses @@ -133,6 +139,10 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION)); #if FVK_DEBUG_FLAGS == FVK_DEBUG_PROFILING + #ifndef NDEBUG + #error PROFILING is meaningless in DEBUG mode. + #endif + #define FVK_SYSTRACE_CONTEXT() #define FVK_SYSTRACE_START(marker) #define FVK_SYSTRACE_END() @@ -186,14 +196,16 @@ constexpr static const int FVK_REQUIRED_VERSION_MINOR = 1; // buffers that have been submitted but have not yet finished rendering. Note that Filament can // issue multiple commit calls in a single frame, and that we use a triple buffered swap chain on // some platforms. -constexpr static const int FVK_MAX_COMMAND_BUFFERS = 10; +// +// Heuristic: Triple Buffering (3) multiplied by maximum number of renderpasses (15). +constexpr static const int FVK_MAX_COMMAND_BUFFERS = 3 * 15; // Number of command buffer submissions that should occur before an unused pipeline is removed // from the cache. // // If this number is low, VkPipeline construction will occur frequently, which can // be extremely slow. If this number is high, the memory footprint will be large. -constexpr static const int FVK_MAX_PIPELINE_AGE = 10; +constexpr static const int FVK_MAX_PIPELINE_AGE = FVK_MAX_COMMAND_BUFFERS; // VulkanPipelineCache does not track which command buffers contain references to which pipelines, // instead it simply waits for at least FVK_MAX_COMMAND_BUFFERS submissions to occur before diff --git a/filament/backend/src/vulkan/VulkanContext.cpp b/filament/backend/src/vulkan/VulkanContext.cpp index 576fff38e178..7c11a47551ff 100644 --- a/filament/backend/src/vulkan/VulkanContext.cpp +++ b/filament/backend/src/vulkan/VulkanContext.cpp @@ -25,15 +25,11 @@ #include #include -#include #include // for std::max using namespace bluevk; -using utils::FixedCapacityVector; - - namespace { } // end anonymous namespace @@ -113,7 +109,7 @@ void VulkanTimestamps::clearQuery(uint32_t queryIndex) { } void VulkanTimestamps::beginQuery(VulkanCommandBuffer const* commands, - VulkanTimerQuery* query) { + fvkmemory::resource_ptr query) { uint32_t const index = query->getStartingQueryIndex(); auto const cmdbuffer = commands->buffer(); @@ -125,19 +121,20 @@ void VulkanTimestamps::beginQuery(VulkanCommandBuffer const* commands, } void VulkanTimestamps::endQuery(VulkanCommandBuffer const* commands, - VulkanTimerQuery const* query) { + fvkmemory::resource_ptr query) { uint32_t const index = query->getStoppingQueryIndex(); vkCmdWriteTimestamp(commands->buffer(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mPool, index); } -VulkanTimestamps::QueryResult VulkanTimestamps::getResult(VulkanTimerQuery const* query) { +VulkanTimestamps::QueryResult VulkanTimestamps::getResult( + fvkmemory::resource_ptr query) { uint32_t const index = query->getStartingQueryIndex(); QueryResult result; size_t const dataSize = result.size() * sizeof(uint64_t); VkDeviceSize const stride = sizeof(uint64_t) * 2; VkResult vkresult = - vkGetQueryPoolResults(mDevice, mPool, index, 2, dataSize, (void*) result.data(), - stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT); + vkGetQueryPoolResults(mDevice, mPool, index, 2, dataSize, (void*) result.data(), stride, + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT); FILAMENT_CHECK_POSTCONDITION(vkresult == VK_SUCCESS || vkresult == VK_NOT_READY) << "vkGetQueryPoolResults error: " << static_cast(vkresult); if (vkresult == VK_NOT_READY) { diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 68c44dfdcee5..67c4e52a9b7b 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -21,6 +21,8 @@ #include "VulkanImageUtility.h" #include "VulkanUtility.h" +#include "vulkan/memory/ResourcePointer.h" + #include #include #include @@ -41,10 +43,10 @@ struct VulkanTimerQuery; struct VulkanCommandBuffer; struct VulkanAttachment { - VulkanTexture* texture = nullptr; + fvkmemory::resource_ptr texture; uint8_t level = 0; uint8_t layerCount = 1; - uint16_t layer = 0; + uint8_t layer = 0; bool isDepth() const; VkImage getImage() const; @@ -70,9 +72,11 @@ class VulkanTimestamps { std::tuple getNextQuery(); void clearQuery(uint32_t queryIndex); - void beginQuery(VulkanCommandBuffer const* commands, VulkanTimerQuery* query); - void endQuery(VulkanCommandBuffer const* commands, VulkanTimerQuery const* query); - QueryResult getResult(VulkanTimerQuery const* query); + void beginQuery(VulkanCommandBuffer const* commands, + fvkmemory::resource_ptr query); + void endQuery(VulkanCommandBuffer const* commands, + fvkmemory::resource_ptr query); + QueryResult getResult(fvkmemory::resource_ptr query); private: VkDevice mDevice; @@ -82,7 +86,9 @@ class VulkanTimestamps { }; struct VulkanRenderPass { - VulkanRenderTarget* renderTarget; + // Between the begin and end command render pass we cache the command buffer + VulkanCommandBuffer* commandBuffer; + fvkmemory::resource_ptr renderTarget; VkRenderPass renderPass; RenderPassParams params; int currentSubpass; diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index bb72633af65e..9bfac220f4eb 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -26,6 +26,8 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" +#include "memory/ResourceManager.h" +#include "memory/ResourcePointer.h" #include @@ -194,23 +196,21 @@ Dispatcher VulkanDriver::getDispatcher() const noexcept { VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& context, Platform::DriverConfig const& driverConfig) noexcept : mPlatform(platform), + mResourceManager(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck), mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(), mPlatform->getDevice())), mContext(context), - mResourceAllocator(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck), - mResourceManager(&mResourceAllocator), - mThreadSafeResourceManager(&mResourceAllocator), mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(), - mPlatform->getGraphicsQueueFamilyIndex(), - nullptr, 0, &mContext, &mResourceAllocator), - mPipelineLayoutCache(mPlatform->getDevice(), &mResourceAllocator), + mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(), + mPlatform->getProtectedGraphicsQueueFamilyIndex(), &mContext), + mPipelineLayoutCache(mPlatform->getDevice()), mPipelineCache(mPlatform->getDevice(), mAllocator), mStagePool(mAllocator, &mCommands), mFramebufferCache(mPlatform->getDevice()), mSamplerCache(mPlatform->getDevice()), mBlitter(mPlatform->getPhysicalDevice(), &mCommands), mReadPixels(mPlatform->getDevice()), - mDescriptorSetManager(mPlatform->getDevice(), &mResourceAllocator), + mDescriptorSetManager(mPlatform->getDevice(), &mResourceManager), mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported), mStereoscopicType(driverConfig.stereoscopicType) { @@ -300,11 +300,10 @@ void VulkanDriver::terminate() { // to those commands are no longer referenced. finish(0); - // Command buffers should come first since it might have commands depending on resources that - // are about to be destroyed. - mCommands.terminate(); + mCurrentSwapChain = {}; + mDefaultRenderTarget = {}; + mBoundPipeline = {}; - mResourceManager.clear(); mTimestamps.reset(); mBlitter.terminate(); @@ -313,6 +312,8 @@ void VulkanDriver::terminate() { // Allow the stage pool to clean up. mStagePool.gc(); + mCommands.terminate(); + mStagePool.terminate(); mPipelineCache.terminate(); mFramebufferCache.reset(); @@ -320,8 +321,11 @@ void VulkanDriver::terminate() { mDescriptorSetManager.terminate(); mPipelineLayoutCache.terminate(); + // Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset. + mResourceManager.terminate(); + #if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) - mResourceAllocator.print(); + mResourceManager.print(); #endif vmaDestroyAllocator(mAllocator); @@ -348,15 +352,17 @@ void VulkanDriver::tick(int) { // been destroyed for safe destruction, due to outstanding command buffers and triple buffering. void VulkanDriver::collectGarbage() { FVK_SYSTRACE_SCOPE(); - // Command buffers need to be submitted and completed before other resources can be gc'd. And - // its gc() function carrys out the *wait*. + // Command buffers need to be submitted and completed before other resources can be gc'd. mCommands.gc(); + mDescriptorSetManager.clearHistory(); mStagePool.gc(); mFramebufferCache.gc(); mPipelineCache.gc(); + mResourceManager.gc(); + #if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) - mResourceAllocator.print(); + mResourceManager.print(); #endif } void VulkanDriver::beginFrame(int64_t monotonic_clock_ns, @@ -388,13 +394,10 @@ void VulkanDriver::updateDescriptorSetBuffer( backend::BufferObjectHandle boh, uint32_t offset, uint32_t size) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("updateDescriptorSetBuffer"); - - VulkanDescriptorSet* set = mResourceAllocator.handle_cast(dsh); - VulkanBufferObject* obj = mResourceAllocator.handle_cast(boh); - mDescriptorSetManager.updateBuffer(set, binding, obj, offset, size); - FVK_SYSTRACE_END(); + FVK_SYSTRACE_SCOPE(); + auto set = resource_ptr::cast(&mResourceManager, dsh); + auto buffer = resource_ptr::cast(&mResourceManager, boh); + mDescriptorSetManager.updateBuffer(set, binding, buffer, offset, size); } void VulkanDriver::updateDescriptorSetTexture( @@ -402,13 +405,12 @@ void VulkanDriver::updateDescriptorSetTexture( backend::descriptor_binding_t binding, backend::TextureHandle th, SamplerParams params) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("updateDescriptorSetTexture"); - VulkanDescriptorSet* set = mResourceAllocator.handle_cast(dsh); - VulkanTexture* texture = mResourceAllocator.handle_cast(th); + FVK_SYSTRACE_SCOPE(); + auto set = resource_ptr::cast(&mResourceManager, dsh); + auto texture = resource_ptr::cast(&mResourceManager, th); + VkSampler const vksampler = mSamplerCache.getSampler(params); mDescriptorSetManager.updateSampler(set, binding, texture, vksampler); - FVK_SYSTRACE_END(); } void VulkanDriver::flush(int) { @@ -428,129 +430,117 @@ void VulkanDriver::finish(int dummy) { void VulkanDriver::createRenderPrimitiveR(Handle rph, Handle vbh, Handle ibh, PrimitiveType pt) { - auto rp = mResourceAllocator.construct(rph, - &mResourceAllocator, pt, vbh, ibh); - mResourceManager.acquire(rp); + auto vb = resource_ptr::cast(&mResourceManager, vbh); + auto ib = resource_ptr::cast(&mResourceManager, ibh); + auto ptr = resource_ptr::make(&mResourceManager, rph, pt, vb, ib); + ptr.inc(); } void VulkanDriver::destroyRenderPrimitive(Handle rph) { if (!rph) { return; } - auto rp = mResourceAllocator.handle_cast(rph); - mResourceManager.release(rp); + auto ptr = resource_ptr::cast(&mResourceManager, rph); + ptr.dec(); } void VulkanDriver::createVertexBufferInfoR(Handle vbih, uint8_t bufferCount, uint8_t attributeCount, AttributeArray attributes) { - auto vbi = mResourceAllocator.construct(vbih, - bufferCount, attributeCount, attributes); - mResourceManager.acquire(vbi); + auto vbi = resource_ptr::make(&mResourceManager, vbih, bufferCount, + attributeCount, attributes); + vbi.inc(); } void VulkanDriver::destroyVertexBufferInfo(Handle vbih) { if (!vbih) { return; } - auto vbi = mResourceAllocator.handle_cast(vbih); - mResourceManager.release(vbi); + auto vbi = resource_ptr::cast(&mResourceManager, vbih); + vbi.dec(); } - -void VulkanDriver::createVertexBufferR(Handle vbh, - uint32_t vertexCount, Handle vbih) { - auto vertexBuffer = mResourceAllocator.construct(vbh, - mContext, mStagePool, &mResourceAllocator, vertexCount, vbih); - mResourceManager.acquire(vertexBuffer); +void VulkanDriver::createVertexBufferR(Handle vbh, uint32_t vertexCount, + Handle vbih) { + auto vbi = resource_ptr::cast(&mResourceManager, vbih); + auto vb = resource_ptr::make(&mResourceManager, vbh, mContext, mStagePool, + vertexCount, vbi); + vb.inc(); } void VulkanDriver::destroyVertexBuffer(Handle vbh) { if (!vbh) { return; } - auto vertexBuffer = mResourceAllocator.handle_cast(vbh); - mResourceManager.release(vertexBuffer); + auto vb = resource_ptr::cast(&mResourceManager, vbh); + vb.dec(); } void VulkanDriver::createIndexBufferR(Handle ibh, ElementType elementType, uint32_t indexCount, BufferUsage usage) { auto elementSize = (uint8_t) getElementTypeSize(elementType); - auto indexBuffer = mResourceAllocator.construct(ibh, mAllocator, mStagePool, + auto ib = resource_ptr::make(&mResourceManager, ibh, mAllocator, mStagePool, elementSize, indexCount); - mResourceManager.acquire(indexBuffer); + ib.inc(); } void VulkanDriver::destroyIndexBuffer(Handle ibh) { if (!ibh) { return; } - auto indexBuffer = mResourceAllocator.handle_cast(ibh); - mResourceManager.release(indexBuffer); + auto ib = resource_ptr::cast(&mResourceManager, ibh); + ib.dec(); } void VulkanDriver::createBufferObjectR(Handle boh, uint32_t byteCount, BufferObjectBinding bindingType, BufferUsage usage) { - auto bufferObject = mResourceAllocator.construct(boh, mAllocator, - mStagePool, byteCount, bindingType); - mResourceManager.acquire(bufferObject); + auto bo = resource_ptr::make(&mResourceManager, boh, mAllocator, mStagePool, + byteCount, bindingType); + bo.inc(); } void VulkanDriver::destroyBufferObject(Handle boh) { if (!boh) { return; } - auto bufferObject = mResourceAllocator.handle_cast(boh); - mResourceManager.release(bufferObject); + auto bo = resource_ptr::cast(&mResourceManager, boh); + bo.dec(); } void VulkanDriver::createTextureR(Handle th, SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, TextureUsage usage) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("createTexture"); + FVK_SYSTRACE_SCOPE(); + auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), + mPlatform->getPhysicalDevice(), mContext, mAllocator, &mResourceManager, &mCommands, + target, levels, format, samples, w, h, depth, usage, mStagePool); - auto vktexture = mResourceAllocator.construct(th, mPlatform->getDevice(), - mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, &mResourceAllocator, - target, levels, - format, samples, w, h, depth, usage, mStagePool); - mResourceManager.acquire(vktexture); + // Do transition to default layout. + VulkanCommandBuffer& commandsBuf = mCommands.get(); + auto const& primaryViewRange = texture->getPrimaryViewRange(); + auto const defaultLayout = texture->getDefaultLayout(); + texture->transitionLayout(&commandsBuf, primaryViewRange, defaultLayout); - FVK_SYSTRACE_END(); + texture.inc(); } -//void VulkanDriver::createTextureSwizzledR(Handle th, SamplerType target, uint8_t levels, -// TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, -// TextureUsage usage, -// TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) { -// TextureSwizzle swizzleArray[] = {r, g, b, a}; -// const VkComponentMapping swizzleMap = getSwizzleMap(swizzleArray); -// auto vktexture = mResourceAllocator.construct(th, mPlatform->getDevice(), -// mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, &mResourceAllocator, -// target, levels, format, samples, w, h, depth, usage, mStagePool, -// false /*heap allocated */, swizzleMap); -// mResourceManager.acquire(vktexture); -//} - void VulkanDriver::createTextureViewR(Handle th, Handle srch, uint8_t baseLevel, uint8_t levelCount) { - VulkanTexture const* src = mResourceAllocator.handle_cast(srch); - auto vktexture = mResourceAllocator.construct(th, mPlatform->getDevice(), - mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, &mResourceAllocator, - src, baseLevel, levelCount); - mResourceManager.acquire(vktexture); + auto src = resource_ptr::cast(&mResourceManager, srch); + auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), + mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, baseLevel, + levelCount); + texture.inc(); } void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle srch, backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, backend::TextureSwizzle a) { - TextureSwizzle const swizzleArray[] = {r, g, b, a}; - VkComponentMapping const swizzle = getSwizzleMap(swizzleArray); - - VulkanTexture const* src = mResourceAllocator.handle_cast(srch); - auto vktexture = mResourceAllocator.construct(th, mPlatform->getDevice(), - mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, &mResourceAllocator, - src, swizzle); - mResourceManager.acquire(vktexture); + TextureSwizzle const swizzleArray[] = {r, g, b, a}; + VkComponentMapping const swizzle = getSwizzleMap(swizzleArray); + auto src = resource_ptr::cast(&mResourceManager, srch); + auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), + mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle); + texture.inc(); } void VulkanDriver::createTextureExternalImageR(Handle th, backend::TextureFormat format, @@ -573,39 +563,36 @@ void VulkanDriver::destroyTexture(Handle th) { if (!th) { return; } - auto texture = mResourceAllocator.handle_cast(th); - mResourceManager.release(texture); + auto texture = resource_ptr::cast(&mResourceManager, th); + texture.dec(); } void VulkanDriver::createProgramR(Handle ph, Program&& program) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("createProgram"); - auto vkprogram - = mResourceAllocator.construct(ph, mPlatform->getDevice(), program); - mResourceManager.acquire(vkprogram); - FVK_SYSTRACE_END(); + FVK_SYSTRACE_SCOPE(); + auto vprogram = resource_ptr::make(&mResourceManager, ph, mPlatform->getDevice(), + program); + vprogram.inc(); } void VulkanDriver::destroyProgram(Handle ph) { if (!ph) { return; } - auto vkprogram = mResourceAllocator.handle_cast(ph); - mResourceManager.release(vkprogram); + auto vprogram = resource_ptr::cast(&mResourceManager, ph); + vprogram.dec(); } void VulkanDriver::createDefaultRenderTargetR(Handle rth, int) { - assert_invariant(mDefaultRenderTarget == nullptr); - VulkanRenderTarget* renderTarget = mResourceAllocator.construct(rth); + assert_invariant(!mDefaultRenderTarget); + auto renderTarget = resource_ptr::make(&mResourceManager, rth); mDefaultRenderTarget = renderTarget; - mResourceManager.acquire(renderTarget); } void VulkanDriver::createRenderTargetR(Handle rth, TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("createRenderTarget"); + + FVK_SYSTRACE_SCOPE(); UTILS_UNUSED_IN_RELEASE math::vec2 tmin = {std::numeric_limits::max()}; UTILS_UNUSED_IN_RELEASE math::vec2 tmax = {0}; @@ -615,10 +602,10 @@ void VulkanDriver::createRenderTargetR(Handle rth, for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) { if (color[i].handle) { colorTargets[i] = { - .texture = mResourceAllocator.handle_cast(color[i].handle), + .texture = resource_ptr::cast(&mResourceManager, color[i].handle), .level = color[i].level, .layerCount = layerCount, - .layer = color[i].layer, + .layer = (uint8_t) color[i].layer, }; UTILS_UNUSED_IN_RELEASE VkExtent2D extent = colorTargets[i].getExtent2D(); tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) }; @@ -630,10 +617,10 @@ void VulkanDriver::createRenderTargetR(Handle rth, VulkanAttachment depthStencil[2] = {}; if (depth.handle) { depthStencil[0] = { - .texture = mResourceAllocator.handle_cast(depth.handle), + .texture = resource_ptr::cast(&mResourceManager, depth.handle), .level = depth.level, .layerCount = layerCount, - .layer = depth.layer, + .layer = (uint8_t) depth.layer, }; UTILS_UNUSED_IN_RELEASE VkExtent2D extent = depthStencil[0].getExtent2D(); tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) }; @@ -643,10 +630,10 @@ void VulkanDriver::createRenderTargetR(Handle rth, if (stencil.handle) { depthStencil[1] = { - .texture = mResourceAllocator.handle_cast(stencil.handle), + .texture = resource_ptr::cast(&mResourceManager, stencil.handle), .level = stencil.level, .layerCount = layerCount, - .layer = stencil.layer, + .layer = (uint8_t) stencil.layer, }; UTILS_UNUSED_IN_RELEASE VkExtent2D extent = depthStencil[1].getExtent2D(); tmin = { std::min(tmin.x, extent.width), std::min(tmin.y, extent.height) }; @@ -660,13 +647,10 @@ void VulkanDriver::createRenderTargetR(Handle rth, assert_invariant(tmin == tmax); assert_invariant(tmin.x >= width && tmin.y >= height); - auto renderTarget = mResourceAllocator.construct(rth, - mPlatform->getDevice(), mPlatform->getPhysicalDevice(), mContext, mAllocator, - &mCommands, &mResourceAllocator, width, height, samples, colorTargets, depthStencil, - mStagePool, layerCount); - mResourceManager.acquire(renderTarget); - - FVK_SYSTRACE_END(); + auto rt = resource_ptr::make(&mResourceManager, rth, mPlatform->getDevice(), + mPlatform->getPhysicalDevice(), mContext, &mResourceManager, mAllocator, &mCommands, + width, height, samples, colorTargets, depthStencil, mStagePool, layerCount); + rt.inc(); } void VulkanDriver::destroyRenderTarget(Handle rth) { @@ -674,16 +658,26 @@ void VulkanDriver::destroyRenderTarget(Handle rth) { return; } - VulkanRenderTarget* rt = mResourceAllocator.handle_cast(rth); + auto rt = resource_ptr::cast(&mResourceManager, rth); if (UTILS_UNLIKELY(rt == mDefaultRenderTarget)) { - mDefaultRenderTarget = nullptr; + mDefaultRenderTarget = {}; + } else { + rt.dec(); } - mResourceManager.release(rt); } void VulkanDriver::createFenceR(Handle fh, int) { - VulkanCommandBuffer* cmdbuf = &mCommands.get(); - mResourceAllocator.construct(fh, cmdbuf->getFenceStatus()); + VulkanCommandBuffer* cmdbuf; + if (mCurrentRenderPass.commandBuffer) { + cmdbuf = mCurrentRenderPass.commandBuffer; + } else { + cmdbuf = &mCommands.get(); + } + // Note at this point, the fence has already been constructed via createFenceS, so we just tag + // it with appropriate VulkanCmdFence, which is associated with the current, recording command + // buffer. + auto fence = resource_ptr::cast(&mResourceManager, fh); + fence->fence = cmdbuf->getFenceStatus(); } void VulkanDriver::createSwapChainR(Handle sch, void* nativeWindow, uint64_t flags) { @@ -692,9 +686,15 @@ void VulkanDriver::createSwapChainR(Handle sch, void* nativeWindow, << utils::io::endl; flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE); } - auto swapChain = mResourceAllocator.construct(sch, mPlatform, mContext, - mAllocator, &mCommands, &mResourceAllocator, mStagePool, nativeWindow, flags); - mResourceManager.acquire(swapChain); + if (flags & backend::SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) { + if (!isProtectedContentSupported()) { + FVK_LOGW << "protected swapchain requested, but Platform does not support it" + << utils::io::endl; + } + } + auto swapChain = resource_ptr::make(&mResourceManager, sch, mPlatform, + mContext, &mResourceManager, mAllocator, &mCommands, mStagePool, nativeWindow, flags); + swapChain.inc(); } void VulkanDriver::createSwapChainHeadlessR(Handle sch, uint32_t width, @@ -705,10 +705,10 @@ void VulkanDriver::createSwapChainHeadlessR(Handle sch, uint32_t wi flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE); } assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions."); - auto swapChain = mResourceAllocator.construct(sch, mPlatform, mContext, - mAllocator, &mCommands, &mResourceAllocator, mStagePool, - nullptr, flags, VkExtent2D{width, height}); - mResourceManager.acquire(swapChain); + auto swapChain = resource_ptr::make(&mResourceManager, sch, mPlatform, + mContext, &mResourceManager, mAllocator, &mCommands, mStagePool, nullptr, flags, + VkExtent2D{width, height}); + swapChain.inc(); } void VulkanDriver::createTimerQueryR(Handle tqh, int) { @@ -717,123 +717,117 @@ void VulkanDriver::createTimerQueryR(Handle tqh, int) { void VulkanDriver::createDescriptorSetLayoutR(Handle dslh, backend::DescriptorSetLayout&& info) { - VulkanDescriptorSetLayout* layout = mResourceAllocator.construct( - dslh, info); - - // This will create a VkDescriptorSetLayout (which is cached) for this object. + auto layout = resource_ptr::make(&mResourceManager, dslh, info); mDescriptorSetManager.initVkLayout(layout); - mResourceManager.acquire(layout); + layout.inc(); } void VulkanDriver::createDescriptorSetR(Handle dsh, Handle dslh) { - FVK_SYSTRACE_CONTEXT(); - FVK_SYSTRACE_START("createDescriptorSet"); - - auto layout = mResourceAllocator.handle_cast(dslh); - mDescriptorSetManager.createSet(dsh, layout); - - auto set = mResourceAllocator.handle_cast(dsh); - mResourceManager.acquire(set); - - FVK_SYSTRACE_END(); + FVK_SYSTRACE_SCOPE(); + fvkmemory::resource_ptr layout = + fvkmemory::resource_ptr::cast(&mResourceManager, dslh); + auto set = mDescriptorSetManager.createSet(dsh, layout); + set.inc(); } Handle VulkanDriver::createVertexBufferInfoS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createVertexBufferS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createIndexBufferS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createBufferObjectS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTextureS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTextureViewS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTextureViewSwizzleS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTextureExternalImageS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTextureExternalImagePlaneS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::importTextureS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createRenderPrimitiveS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createProgramS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createDefaultRenderTargetS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createRenderTargetS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createFenceS() noexcept { - return mResourceAllocator.initHandle(); + auto handle = mResourceManager.allocHandle(); + auto fence = resource_ptr::make(&mResourceManager, handle); + fence.inc(); + return handle; } Handle VulkanDriver::createSwapChainS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createSwapChainHeadlessS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createTimerQueryS() noexcept { // The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen // before createTimerQueryR is executed. - Handle tqh - = mResourceAllocator.initHandle(mTimestamps->getNextQuery()); - auto query = mResourceAllocator.handle_cast(tqh); - mThreadSafeResourceManager.acquire(query); - return tqh; + auto query = resource_ptr::construct(&mResourceManager, + mTimestamps->getNextQuery()); + query.inc(); + return Handle(query.id()); } Handle VulkanDriver::createDescriptorSetLayoutS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } Handle VulkanDriver::createDescriptorSetS() noexcept { - return mResourceAllocator.allocHandle(); + return mResourceManager.allocHandle(); } void VulkanDriver::destroySwapChain(Handle sch) { if (!sch) { return; } - VulkanSwapChain* swapChain = mResourceAllocator.handle_cast(sch); + auto swapChain = resource_ptr::cast(&mResourceManager, sch); if (mCurrentSwapChain == swapChain) { - mCurrentSwapChain = nullptr; + mCurrentSwapChain = {}; } - mResourceManager.release(swapChain); + swapChain.dec(); } void VulkanDriver::destroyStream(Handle sh) { @@ -843,19 +837,18 @@ void VulkanDriver::destroyTimerQuery(Handle tqh) { if (!tqh) { return; } - auto vtq = mResourceAllocator.handle_cast(tqh); - mThreadSafeResourceManager.release(vtq); + auto vtq = resource_ptr::cast(&mResourceManager, tqh); + vtq.dec(); } void VulkanDriver::destroyDescriptorSetLayout(Handle dslh) { - VulkanDescriptorSetLayout* layout = mResourceAllocator.handle_cast(dslh); - mResourceManager.release(layout); + auto layout = resource_ptr::cast(&mResourceManager, dslh); + layout.dec(); } void VulkanDriver::destroyDescriptorSet(Handle dsh) { - mDescriptorSetManager.destroySet(dsh); - VulkanDescriptorSet* set = mResourceAllocator.handle_cast(dsh); - mResourceManager.release(set); + auto set = resource_ptr::cast(&mResourceManager, dsh); + set.dec(); } Handle VulkanDriver::createStreamNative(void* nativeStream) { @@ -881,11 +874,14 @@ void VulkanDriver::updateStreams(CommandStream* driver) { } void VulkanDriver::destroyFence(Handle fh) { - mResourceAllocator.destruct(fh); + auto fence = resource_ptr::cast(&mResourceManager, fh); + fence.dec(); } FenceStatus VulkanDriver::getFenceStatus(Handle fh) { - auto& cmdfence = mResourceAllocator.handle_cast(fh)->fence; + auto fence = resource_ptr::cast(&mResourceManager, fh); + + auto& cmdfence = fence->fence; if (!cmdfence) { // If wait is called before a fence actually exists, we return timeout. This matches the // current behavior in OpenGLDriver, but we should eventually reconsider a different error @@ -899,10 +895,11 @@ FenceStatus VulkanDriver::getFenceStatus(Handle fh) { return FenceStatus::CONDITION_SATISFIED; } + // Two other states are possible: - // - VK_INCOMPLETE: the corresponding buffer has not yet been submitted. - // - VK_NOT_READY: the buffer has been submitted but not yet signaled. - // In either case, we return TIMEOUT_EXPIRED to indicate the fence has not been signaled. + // - VK_INCOMPLETE: the corresponding buffer has not yet been submitted. + // - VK_NOT_READY: the buffer has been submitted but not yet signaled. + // In either case, we return TIMEOUT_EXPIRED to indicate the fence has not been signaled. return FenceStatus::TIMEOUT_EXPIRED; } @@ -1088,16 +1085,16 @@ size_t VulkanDriver::getMaxUniformBufferSize() { void VulkanDriver::setVertexBufferObject(Handle vbh, uint32_t index, Handle boh) { - auto vb = mResourceAllocator.handle_cast(vbh); - auto bo = mResourceAllocator.handle_cast(boh); + auto vb = resource_ptr::cast(&mResourceManager, vbh); + auto bo = resource_ptr::cast(&mResourceManager, boh); assert_invariant(bo->bindingType == BufferObjectBinding::VERTEX); - vb->setBuffer(mResourceAllocator, bo, index); + vb->setBuffer(bo, index); } void VulkanDriver::updateIndexBuffer(Handle ibh, BufferDescriptor&& p, uint32_t byteOffset) { VulkanCommandBuffer& commands = mCommands.get(); - auto ib = mResourceAllocator.handle_cast(ibh); + auto ib = resource_ptr::cast(&mResourceManager, ibh); commands.acquire(ib); ib->buffer.loadFromCpu(commands.buffer(), p.buffer, byteOffset, p.size); @@ -1108,7 +1105,7 @@ void VulkanDriver::updateBufferObject(Handle boh, BufferDescript uint32_t byteOffset) { VulkanCommandBuffer& commands = mCommands.get(); - auto bo = mResourceAllocator.handle_cast(boh); + auto bo = resource_ptr::cast(&mResourceManager, boh); commands.acquire(bo); bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size); @@ -1118,11 +1115,10 @@ void VulkanDriver::updateBufferObject(Handle boh, BufferDescript void VulkanDriver::updateBufferObjectUnsynchronized(Handle boh, BufferDescriptor&& bd, uint32_t byteOffset) { VulkanCommandBuffer& commands = mCommands.get(); - auto bo = mResourceAllocator.handle_cast(boh); + auto bo = resource_ptr::cast(&mResourceManager, boh); commands.acquire(bo); // TODO: implement unsynchronized version bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size); - mResourceManager.acquire(bo); scheduleDestroy(std::move(bd)); } @@ -1138,8 +1134,8 @@ void VulkanDriver::resetBufferObject(Handle boh) { void VulkanDriver::update3DImage(Handle th, uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth, PixelBufferDescriptor&& data) { - mResourceAllocator.handle_cast(th)->updateImage(data, width, height, depth, - xoffset, yoffset, zoffset, level); + auto texture = resource_ptr::cast(&mResourceManager, th); + texture->updateImage(data, width, height, depth, xoffset, yoffset, zoffset, level); scheduleDestroy(std::move(data)); } @@ -1147,7 +1143,7 @@ void VulkanDriver::setupExternalImage(void* image) { } TimerQueryResult VulkanDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { - VulkanTimerQuery* vtq = mResourceAllocator.handle_cast(tqh); + auto vtq = resource_ptr::cast(&mResourceManager, tqh); if (!vtq->isCompleted()) { return TimerQueryResult::NOT_READY; } @@ -1185,7 +1181,7 @@ void VulkanDriver::setExternalStream(Handle th, Handle sh) } void VulkanDriver::generateMipmaps(Handle th) { - auto* const t = mResourceAllocator.handle_cast(th); + auto t = resource_ptr::cast(&mResourceManager, th); assert_invariant(t); int32_t layerCount = int32_t(t->depth); @@ -1194,9 +1190,10 @@ void VulkanDriver::generateMipmaps(Handle th) { layerCount *= 6; } + assert_invariant(layerCount < 1 << (sizeof(VulkanAttachment::layerCount) * 8)); + // FIXME: the loop below can perform many layout transitions and back. We should be // able to optimize that. - uint8_t level = 0; int32_t srcw = int32_t(t->width); int32_t srch = int32_t(t->height); @@ -1208,12 +1205,18 @@ void VulkanDriver::generateMipmaps(Handle th) { // TODO: there should be a way to do this using layerCount in vkBlitImage // TODO: vkBlitImage should be able to handle 3D textures too - for (int32_t layer = 0; layer < layerCount; layer++) { - mBlitter.blit(VK_FILTER_LINEAR, - { .texture = t, .level = uint8_t(level + 1), .layer = (uint16_t)layer }, - dstOffsets, - { .texture = t, .level = uint8_t(level ), .layer = (uint16_t)layer }, - srcOffsets); + for (uint8_t layer = 0; layer < layerCount; layer++) { + VulkanAttachment dst { + .level = uint8_t(level + 1), + .layer = layer, + }; + dst.texture = t; + VulkanAttachment src { + .level = uint8_t(level), + .layer = layer, + }; + src.texture = t; + mBlitter.blit(VK_FILTER_LINEAR, dst, dstOffsets, src, srcOffsets); } level++; @@ -1232,16 +1235,20 @@ void VulkanDriver::compilePrograms(CompilerPriorityQueue priority, void VulkanDriver::beginRenderPass(Handle rth, const RenderPassParams& params) { FVK_SYSTRACE_SCOPE(); - VulkanRenderTarget* const rt = mResourceAllocator.handle_cast(rth); - VkExtent2D const& extent = rt->getExtent(); + auto rt = resource_ptr::cast(&mResourceManager, rth); + VkExtent2D const extent = rt->getExtent(); + assert_invariant(rt == mDefaultRenderTarget || extent.width > 0 && extent.height > 0); + VulkanCommandBuffer* commandBuffer = rt->isProtected() ? + &mCommands.getProtected() : &mCommands.get(); + // Filament has the expectation that the contents of the swap chain are not preserved on the // first render pass. Note however that its contents are often preserved on subsequent render // passes, due to multiple views. TargetBufferFlags discardStart = params.flags.discardStart; if (rt->isSwapChain()) { - VulkanSwapChain* sc = mCurrentSwapChain; + fvkmemory::resource_ptr sc = mCurrentSwapChain; assert_invariant(sc); if (sc->isFirstRenderPass()) { discardStart |= TargetBufferFlags::COLOR; @@ -1260,8 +1267,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP // If that's the case, we need to change the layout of the texture to DEPTH_SAMPLER, which is a // more general layout. Otherwise, we prefer the DEPTH_ATTACHMENT layout, which is optimal for // the non-sampling case. - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer const cmdbuffer = commands.buffer(); + VkCommandBuffer const cmdbuffer = commandBuffer->buffer(); // Scissor is reset with each render pass // This also takes care of VUID-vkCmdDrawIndexed-None-07832. @@ -1281,6 +1287,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP // Create the VkRenderPass or fetch it from cache. + VulkanFboCache::RenderPassKey rpkey = rt->getRenderPassKey(); rpkey.clear = clearVal; rpkey.discardStart = discardStart; @@ -1296,7 +1303,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP fbkey.renderPass = renderPass; fbkey.layers = 1; - rt->emitBarriersBeginRenderPass(commands); + rt->emitBarriersBeginRenderPass(*commandBuffer); VkFramebuffer vkfb = mFramebufferCache.getFramebuffer(fbkey); @@ -1310,7 +1317,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP #endif // The current command buffer now has references to the render target and its attachments. - commands.acquire(rt); + commandBuffer->acquire(rt); // Populate the structures required for vkCmdBeginRenderPass. VkRenderPassBeginInfo renderPassInfo { @@ -1369,6 +1376,7 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP vkCmdSetViewport(cmdbuffer, 0, 1, &viewport); mCurrentRenderPass = { + .commandBuffer = commandBuffer, .renderTarget = rt, .renderPass = renderPassInfo.renderPass, .params = params, @@ -1379,37 +1387,39 @@ void VulkanDriver::beginRenderPass(Handle rth, const RenderPassP void VulkanDriver::endRenderPass(int) { FVK_SYSTRACE_SCOPE(); - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); vkCmdEndRenderPass(cmdbuffer); - VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget; + auto rt = mCurrentRenderPass.renderTarget; assert_invariant(rt); // Since we might soon be sampling from the render target that we just wrote to, we need a // pipeline barrier between framebuffer writes and shader reads. - rt->emitBarriersEndRenderPass(commands); + rt->emitBarriersEndRenderPass(*mCurrentRenderPass.commandBuffer); mRenderPassFboInfo = {}; - mCurrentRenderPass.renderTarget = nullptr; + mCurrentRenderPass.renderTarget = {}; mCurrentRenderPass.renderPass = VK_NULL_HANDLE; + + mCurrentRenderPass.commandBuffer = nullptr; } void VulkanDriver::nextSubpass(int) { FILAMENT_CHECK_PRECONDITION(mCurrentRenderPass.currentSubpass == 0) << "Only two subpasses are currently supported."; - VulkanRenderTarget* renderTarget = mCurrentRenderPass.renderTarget; + auto renderTarget = mCurrentRenderPass.renderTarget; assert_invariant(renderTarget); assert_invariant(mCurrentRenderPass.params.subpassMask); - vkCmdNextSubpass(mCommands.get().buffer(), VK_SUBPASS_CONTENTS_INLINE); + vkCmdNextSubpass(mCurrentRenderPass.commandBuffer->buffer(), + VK_SUBPASS_CONTENTS_INLINE); mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass, ++mCurrentRenderPass.currentSubpass); if (mCurrentRenderPass.params.subpassMask & 0x1) { - VulkanAttachment subpassInput = renderTarget->getColor0(); + VulkanAttachment& subpassInput = renderTarget->getColor0(); mDescriptorSetManager.updateInputAttachment({}, subpassInput); } } @@ -1419,8 +1429,10 @@ void VulkanDriver::makeCurrent(Handle drawSch, Handle ASSERT_PRECONDITION_NON_FATAL(drawSch == readSch, "Vulkan driver does not support distinct draw/read swap chains."); - VulkanSwapChain* swapChain = mCurrentSwapChain - = mResourceAllocator.handle_cast(drawSch); + + resource_ptr swapChain = + resource_ptr::cast(&mResourceManager, drawSch); + mCurrentSwapChain = swapChain; bool resized = false; swapChain->acquire(resized); @@ -1430,14 +1442,14 @@ void VulkanDriver::makeCurrent(Handle drawSch, Handle } if (UTILS_LIKELY(mDefaultRenderTarget)) { - mDefaultRenderTarget->bindToSwapChain(*swapChain); + mDefaultRenderTarget->bindToSwapChain(swapChain); } } void VulkanDriver::commit(Handle sch) { FVK_SYSTRACE_SCOPE(); - VulkanSwapChain* swapChain = mResourceAllocator.handle_cast(sch); + auto swapChain = resource_ptr::cast(&mResourceManager, sch); // Present the backbuffer after the most recent command buffer submission has finished. swapChain->present(); @@ -1446,9 +1458,9 @@ void VulkanDriver::commit(Handle sch) { void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant value) { assert_invariant(mBoundPipeline.program && "Expect a program when writing to push constants"); - VulkanCommands* commands = &mCommands; - mBoundPipeline.program->writePushConstant(commands, mBoundPipeline.pipelineLayout, stage, index, - value); + assert_invariant(mCurrentRenderPass.commandBuffer && "Should be called within a renderpass"); + mBoundPipeline.program->writePushConstant(mCurrentRenderPass.commandBuffer->buffer(), + mBoundPipeline.pipelineLayout, stage, index, value); } void VulkanDriver::insertEventMarker(char const* string) { @@ -1480,7 +1492,7 @@ void VulkanDriver::stopCapture(int) {} void VulkanDriver::readPixels(Handle src, uint32_t x, uint32_t y, uint32_t width, uint32_t height, PixelBufferDescriptor&& pbd) { - VulkanRenderTarget* srcTarget = mResourceAllocator.handle_cast(src); + auto srcTarget = resource_ptr::cast(&mResourceManager, src); mCommands.flush(); mReadPixels.run( srcTarget, x, y, width, height, mPlatform->getGraphicsQueueFamilyIndex(), @@ -1507,8 +1519,9 @@ void VulkanDriver::resolve( FILAMENT_CHECK_PRECONDITION(mCurrentRenderPass.renderPass == VK_NULL_HANDLE) << "resolve() cannot be invoked inside a render pass."; - auto* const srcTexture = mResourceAllocator.handle_cast(src); - auto* const dstTexture = mResourceAllocator.handle_cast(dst); + auto srcTexture = resource_ptr::cast(&mResourceManager, src); + auto dstTexture = resource_ptr::cast(&mResourceManager, dst); + assert_invariant(srcTexture); assert_invariant(dstTexture); @@ -1549,8 +1562,8 @@ void VulkanDriver::blit( FILAMENT_CHECK_PRECONDITION(mCurrentRenderPass.renderPass == VK_NULL_HANDLE) << "blit() cannot be invoked inside a render pass."; - auto* const srcTexture = mResourceAllocator.handle_cast(src); - auto* const dstTexture = mResourceAllocator.handle_cast(dst); + auto srcTexture = resource_ptr::cast(&mResourceManager, src); + auto dstTexture = resource_ptr::cast(&mResourceManager, dst); FILAMENT_CHECK_PRECONDITION(any(dstTexture->usage & TextureUsage::BLIT_DST)) << "texture doesn't have BLIT_DST"; @@ -1598,8 +1611,8 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers, srcRect.left >= 0 && srcRect.bottom >= 0 && dstRect.left >= 0 && dstRect.bottom >= 0) << "Source and destination rects must be positive."; - VulkanRenderTarget* dstTarget = mResourceAllocator.handle_cast(dst); - VulkanRenderTarget* srcTarget = mResourceAllocator.handle_cast(src); + auto dstTarget = resource_ptr::cast(&mResourceManager, dst); + auto srcTarget = resource_ptr::cast(&mResourceManager, src); VkFilter const vkfilter = (filter == SamplerMagFilter::NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; @@ -1627,20 +1640,19 @@ void VulkanDriver::blitDEPRECATED(TargetBufferFlags buffers, void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { FVK_SYSTRACE_SCOPE(); - - VulkanCommandBuffer* commands = &mCommands.get(); - const VulkanVertexBufferInfo& vbi = - *mResourceAllocator.handle_cast(pipelineState.vertexBufferInfo); + auto commands = mCurrentRenderPass.commandBuffer; + auto vbi = resource_ptr::cast(&mResourceManager, + pipelineState.vertexBufferInfo); Handle programHandle = pipelineState.program; RasterState const& rasterState = pipelineState.rasterState; PolygonOffset const& depthOffset = pipelineState.polygonOffset; - auto* program = mResourceAllocator.handle_cast(programHandle); + auto program = resource_ptr::cast(&mResourceManager, programHandle); commands->acquire(program); // Update the VK raster state. - const VulkanRenderTarget* rt = mCurrentRenderPass.renderTarget; + auto rt = mCurrentRenderPass.renderTarget; VulkanPipelineCache::RasterState const vulkanRasterState{ .cullMode = getCullMode(rasterState.culling), @@ -1669,14 +1681,14 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { VulkanPipelineCache::getPrimitiveTopology(pipelineState.primitiveType); // Declare fixed-size arrays that get passed to the pipeCache and to vkCmdBindVertexBuffers. - VkVertexInputAttributeDescription const* attribDesc = vbi.getAttribDescriptions(); - VkVertexInputBindingDescription const* bufferDesc = vbi.getBufferDescriptions(); + VkVertexInputAttributeDescription const* attribDesc = vbi->getAttribDescriptions(); + VkVertexInputBindingDescription const* bufferDesc = vbi->getBufferDescriptions(); // Push state changes to the VulkanPipelineCache instance. This is fast and does not make VK calls. mPipelineCache.bindProgram(program); mPipelineCache.bindRasterState(vulkanRasterState); mPipelineCache.bindPrimitiveTopology(topology); - mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi.getAttributeCount()); + mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount()); auto& setLayouts = pipelineState.pipelineLayout.setLayout; VulkanDescriptorSetLayout::DescriptorSetLayoutArray layoutList; @@ -1686,7 +1698,8 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { if (!handle) { return VK_NULL_HANDLE; } - auto layout = mResourceAllocator.handle_cast(handle); + auto layout = + resource_ptr::cast(&mResourceManager, handle); layoutCount++; return layout->getVkLayout(); }); @@ -1701,33 +1714,31 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { }; mPipelineCache.bindLayout(pipelineLayout); - mPipelineCache.bindPipeline(commands); + mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer); } void VulkanDriver::bindRenderPrimitive(Handle rph) { FVK_SYSTRACE_SCOPE(); - VulkanCommandBuffer* commands = &mCommands.get(); + VulkanCommandBuffer* commands = mCurrentRenderPass.commandBuffer; VkCommandBuffer cmdbuffer = commands->buffer(); - const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast(rph); - commands->acquire(prim.indexBuffer); - commands->acquire(prim.vertexBuffer); + auto prim = resource_ptr::cast(&mResourceManager, rph); + commands->acquire(prim); // This *must* match the VulkanVertexBufferInfo that was bound in bindPipeline(). But we want // to allow to call this before bindPipeline(), so the validation can only happen in draw() - VulkanVertexBufferInfo const* const vbi = - mResourceAllocator.handle_cast(prim.vertexBuffer->vbih); + auto vbi = prim->vertexBuffer->vbi; uint32_t const bufferCount = vbi->getAttributeCount(); VkDeviceSize const* offsets = vbi->getOffsets(); - VkBuffer const* buffers = prim.vertexBuffer->getVkBuffers(); + VkBuffer const* buffers = prim->vertexBuffer->getVkBuffers(); // Next bind the vertex buffers and index buffer. One potential performance improvement is to // avoid rebinding these if they are already bound, but since we do not (yet) support subranges // it would be rare for a client to make consecutive draw calls with the same render primitive. vkCmdBindVertexBuffers(cmdbuffer, 0, bufferCount, buffers, offsets); - vkCmdBindIndexBuffer(cmdbuffer, prim.indexBuffer->buffer.getGpuBuffer(), 0, - prim.indexBuffer->indexType); + vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getGpuBuffer(), 0, + prim->indexBuffer->indexType); } void VulkanDriver::bindDescriptorSet( @@ -1735,7 +1746,7 @@ void VulkanDriver::bindDescriptorSet( backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) { if (dsh) { - VulkanDescriptorSet* set = mResourceAllocator.handle_cast(dsh); + auto set = resource_ptr::cast(&mResourceManager, dsh); mDescriptorSetManager.bind(setIndex, set, std::move(offsets)); } else { mDescriptorSetManager.unbind(setIndex); @@ -1744,11 +1755,10 @@ void VulkanDriver::bindDescriptorSet( void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) { FVK_SYSTRACE_SCOPE(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); - - mDescriptorSetManager.commit(&commands, mBoundPipeline.pipelineLayout, + mDescriptorSetManager.commit(mCurrentRenderPass.commandBuffer, + mBoundPipeline.pipelineLayout, mBoundPipeline.descriptorSetMask); // Finally, make the actual draw call. TODO: support subranges @@ -1761,9 +1771,9 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins void VulkanDriver::draw(PipelineState state, Handle rph, uint32_t const indexOffset, uint32_t const indexCount, uint32_t const instanceCount) { - VulkanRenderPrimitive* const rp = mResourceAllocator.handle_cast(rph); + auto rp = resource_ptr::cast(&mResourceManager, rph); state.primitiveType = rp->type; - state.vertexBufferInfo = rp->vertexBuffer->vbih; + state.vertexBufferInfo = Handle(rp->vertexBuffer->vbi.id()); bindPipeline(state); bindRenderPrimitive(rph); draw2(indexOffset, indexCount, instanceCount); @@ -1774,8 +1784,7 @@ void VulkanDriver::dispatchCompute(Handle program, math::uint3 workGr } void VulkanDriver::scissor(Viewport scissorBox) { - VulkanCommandBuffer& commands = mCommands.get(); - VkCommandBuffer cmdbuffer = commands.buffer(); + VkCommandBuffer cmdbuffer = mCurrentRenderPass.commandBuffer->buffer(); // TODO: it's a common case that scissor() is called with (0, 0, maxint, maxint) // we should maybe have a fast path for this and avoid vkCmdSetScissor() if possible @@ -1798,19 +1807,19 @@ void VulkanDriver::scissor(Viewport scissorBox) { .extent = { uint32_t(r - l), uint32_t(t - b) } }; - VulkanRenderTarget const* rt = mCurrentRenderPass.renderTarget; + auto rt = mCurrentRenderPass.renderTarget; rt->transformClientRectToPlatform(&scissor); vkCmdSetScissor(cmdbuffer, 0, 1, &scissor); } void VulkanDriver::beginTimerQuery(Handle tqh) { - VulkanTimerQuery* vtq = mResourceAllocator.handle_cast(tqh); + auto vtq = resource_ptr::cast(&mResourceManager, tqh); mTimestamps->beginQuery(&(mCommands.get()), vtq); } void VulkanDriver::endTimerQuery(Handle tqh) { - VulkanTimerQuery* vtq = mResourceAllocator.handle_cast(tqh); - mTimestamps->endQuery(&(mCommands.get()), vtq); + auto vtq = resource_ptr::cast(&mResourceManager, tqh); + mTimestamps->endQuery(&(mCommands.get()), vtq); } void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept { @@ -1842,7 +1851,7 @@ void VulkanDriver::resetState(int) { } void VulkanDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) { - mResourceAllocator.associateHandle(handleId, std::move(tag)); + mResourceManager.associateHandle(handleId, std::move(tag)); } // explicit instantiation of the Dispatcher diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index 7dd952093429..e304b8df4a63 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -24,13 +24,14 @@ #include "VulkanHandles.h" #include "VulkanPipelineCache.h" #include "VulkanReadPixels.h" -#include "VulkanResourceAllocator.h" #include "VulkanSamplerCache.h" #include "VulkanStagePool.h" #include "VulkanUtility.h" #include "backend/DriverEnums.h" #include "caching/VulkanDescriptorSetManager.h" #include "caching/VulkanPipelineLayoutCache.h" +#include "memory/ResourceManager.h" +#include "memory/ResourcePointer.h" #include "DriverBase.h" #include "private/backend/Driver.h" @@ -77,6 +78,9 @@ class VulkanDriver final : public DriverBase { #endif // FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS) private: + template + using resource_ptr = fvkmemory::resource_ptr; + static constexpr uint8_t MAX_SAMPLER_BINDING_COUNT = Program::SAMPLER_BINDING_COUNT; void debugCommandBegin(CommandStream* cmds, bool synchronous, @@ -113,21 +117,16 @@ class VulkanDriver final : public DriverBase { void collectGarbage(); VulkanPlatform* mPlatform = nullptr; + fvkmemory::ResourceManager mResourceManager; std::unique_ptr mTimestamps; - VulkanSwapChain* mCurrentSwapChain = nullptr; - VulkanRenderTarget* mDefaultRenderTarget = nullptr; + resource_ptr mCurrentSwapChain; + resource_ptr mDefaultRenderTarget; VulkanRenderPass mCurrentRenderPass = {}; VmaAllocator mAllocator = VK_NULL_HANDLE; VkDebugReportCallbackEXT mDebugCallback = VK_NULL_HANDLE; VulkanContext mContext = {}; - VulkanResourceAllocator mResourceAllocator; - VulkanResourceManager mResourceManager; - - // Used for resources that are created synchronously and used and destroyed on the backend - // thread. - VulkanThreadSafeResourceManager mThreadSafeResourceManager; VulkanCommands mCommands; VulkanPipelineLayoutCache mPipelineLayoutCache; @@ -142,7 +141,7 @@ class VulkanDriver final : public DriverBase { // This is necessary for us to write to push constants after binding a pipeline. struct { - VulkanProgram* program; + resource_ptr program; VkPipelineLayout pipelineLayout; DescriptorSetMask descriptorSetMask; } mBoundPipeline = {}; diff --git a/filament/backend/src/vulkan/VulkanHandles.cpp b/filament/backend/src/vulkan/VulkanHandles.cpp index 9fda018943bc..dd64779a9026 100644 --- a/filament/backend/src/vulkan/VulkanHandles.cpp +++ b/filament/backend/src/vulkan/VulkanHandles.cpp @@ -22,8 +22,8 @@ #include "VulkanDriver.h" #include "VulkanMemory.h" -#include "VulkanResourceAllocator.h" #include "VulkanUtility.h" +#include "vulkan/memory/ResourcePointer.h" #include "spirv/VulkanSpirvUtils.h" #include @@ -105,9 +105,10 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) { return mask; } -VulkanTexture* initMsaaTexture(VulkanTexture* texture, VkDevice device, +fvkmemory::resource_ptr initMsaaTexture( + fvkmemory::resource_ptr texture, VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, VmaAllocator allocator, - VulkanCommands* commands, VulkanResourceAllocator* handleAllocator, uint8_t levels, + VulkanCommands* commands, fvkmemory::ResourceManager* resManager, uint8_t levels, uint8_t samples, VulkanStagePool& stagePool) { assert_invariant(texture); auto msTexture = texture->getSidecar(); @@ -117,10 +118,9 @@ VulkanTexture* initMsaaTexture(VulkanTexture* texture, VkDevice device, const TextureUsage usage = texture->usage & TextureUsage::ALL_ATTACHMENTS; assert_invariant(static_cast(usage) != 0U); - msTexture = new VulkanTexture(device, physicalDevice, context, allocator, commands, - handleAllocator, texture->target, levels, - texture->format, samples, texture->width, texture->height, texture->depth, usage, - stagePool, true /* heap allocated */); + msTexture = resource_ptr::construct(resManager, device, physicalDevice, + context, allocator, resManager, commands, texture->target, levels, texture->format, + samples, texture->width, texture->height, texture->depth, usage, stagePool); texture->setSidecar(msTexture); } return msTexture; @@ -128,19 +128,18 @@ VulkanTexture* initMsaaTexture(VulkanTexture* texture, VkDevice device, } // anonymous namespace -VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& layout) - : VulkanResource(VulkanResourceType::DESCRIPTOR_SET_LAYOUT), - bitmask(fromBackendLayout(layout)), - count(Count::fromLayoutBitmask(bitmask)) {} - -void VulkanDescriptorSet::acquire(VulkanTexture* texture) { - mResources.acquire(texture); +void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr texture) { + mResources.push_back(texture); } -void VulkanDescriptorSet::acquire(VulkanBufferObject* bufferObject) { - mResources.acquire(bufferObject); +void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr obj) { + mResources.push_back(obj); } +VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& layout) + : bitmask(fromBackendLayout(layout)), + count(Count::fromLayoutBitmask(bitmask)) {} + PushConstantDescription::PushConstantDescription(backend::Program const& program) noexcept { mRangeCount = 0; for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) { @@ -164,9 +163,9 @@ PushConstantDescription::PushConstantDescription(backend::Program const& program } } -void PushConstantDescription::write(VulkanCommands* commands, VkPipelineLayout layout, +void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) { - VulkanCommandBuffer* cmdbuf = &(commands->get()); + uint32_t binaryValue = 0; UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage]; if (std::holds_alternative(value)) { @@ -182,13 +181,12 @@ void PushConstantDescription::write(VulkanCommands* commands, VkPipelineLayout l int const ival = std::get(value); binaryValue = *reinterpret_cast(&ival); } - vkCmdPushConstants(cmdbuf->buffer(), layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE, + vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE, &binaryValue); } VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept : HwProgram(builder.getName()), - VulkanResource(VulkanResourceType::PROGRAM), mInfo(new(std::nothrow) PipelineInfo(builder)), mDevice(device) { @@ -256,23 +254,24 @@ VulkanProgram::~VulkanProgram() { // Creates a special "default" render target (i.e. associated with the swap chain) VulkanRenderTarget::VulkanRenderTarget() : HwRenderTarget(0, 0), - VulkanResource(VulkanResourceType::RENDER_TARGET), mOffscreen(false), mProtected(false), - mResources(nullptr), mInfo(std::make_unique()) { mInfo->rpkey.samples = mInfo->fbkey.samples = 1; } -void VulkanRenderTarget::bindToSwapChain(VulkanSwapChain& swapChain) { +VulkanRenderTarget::~VulkanRenderTarget() = default; + +void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr swapchain) { assert_invariant(!mOffscreen); - VkExtent2D const extent = swapChain.getExtent(); + VkExtent2D const extent = swapchain->getExtent(); width = extent.width; height = extent.height; - mProtected = swapChain.isProtected(); + mProtected = swapchain->isProtected(); - VulkanAttachment color = {.texture = swapChain.getCurrentColor()}; + VulkanAttachment color = {}; + color.texture = swapchain->getCurrentColor(); mInfo->attachments = {color}; auto& fbkey = mInfo->fbkey; @@ -284,33 +283,30 @@ void VulkanRenderTarget::bindToSwapChain(VulkanSwapChain& swapChain) { fbkey.color[0] = color.getImageView(); fbkey.resolve[0] = VK_NULL_HANDLE; - VulkanAttachment depth = {}; - rpkey.depthFormat = depth.getFormat(); - fbkey.depth = VK_NULL_HANDLE; - - if (swapChain.getDepth()) { - depth = {.texture = swapChain.getDepth()}; + if (swapchain->getDepth()) { + VulkanAttachment depth = {}; + depth.texture = swapchain->getDepth(); mInfo->attachments.push_back(depth); mInfo->depthIndex = 1; rpkey.depthFormat = depth.getFormat(); fbkey.depth = depth.getImageView(); + } else { + rpkey.depthFormat = VK_FORMAT_UNDEFINED; + fbkey.depth = VK_NULL_HANDLE; } mInfo->colors.set(0); } VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physicalDevice, - VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, uint32_t width, uint32_t height, uint8_t samples, - VulkanAttachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT], + VulkanContext const& context, fvkmemory::ResourceManager* resourceManager, + VmaAllocator allocator, VulkanCommands* commands, uint32_t width, uint32_t height, + uint8_t samples, VulkanAttachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT], VulkanAttachment depthStencil[2], VulkanStagePool& stagePool, uint8_t layerCount) : HwRenderTarget(width, height), - VulkanResource(VulkanResourceType::RENDER_TARGET), mOffscreen(true), mProtected(false), - mResources(handleAllocator), mInfo(std::make_unique()) { - auto& depth = depthStencil[0]; // Constrain the sample count according to both kinds of sample count masks obtained from @@ -340,6 +336,8 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica continue; } + mProtected |= texture->getIsProtected(); + attachments.push_back(attachment); mInfo->colors.set(index); @@ -347,14 +345,11 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica fbkey.color[index] = attachment.getImageView(); fbkey.resolve[index] = VK_NULL_HANDLE; - mResources.acquire(attachment.texture); - if (samples > 1) { VulkanAttachment msaaAttachment = {}; if (texture->samples == 1) { auto msaaTexture = initMsaaTexture(texture, device, physicalDevice, context, - allocator, commands, handleAllocator, - ((VulkanTexture const*) texture)->levels, samples, stagePool); + allocator, commands, resourceManager, texture->levels, samples, stagePool); if (msaaTexture && msaaTexture->isTransientAttachment()) { rpkey.usesLazilyAllocatedMemory |= (1 << index); } @@ -375,7 +370,6 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica } fbkey.color[index] = msaaAttachment.getImageView(); msaa.push_back(msaaAttachment); - mResources.acquire(msaaAttachment.texture); } } @@ -388,19 +382,18 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica auto depthTexture = depth.texture; mInfo->depthIndex = (uint8_t) attachments.size(); attachments.push_back(depth); - mResources.acquire(depthTexture); fbkey.depth = depth.getImageView(); if (samples > 1) { mInfo->msaaDepthIndex = mInfo->depthIndex; if (depthTexture->samples == 1) { // MSAA depth texture must have the mipmap count of 1 uint8_t const msLevel = 1; - // Create sidecar MSAA texture for the depth attachment if it does not already exist. - auto msaa = initMsaaTexture(depthTexture, device, physicalDevice, context, allocator, - commands, handleAllocator, msLevel, samples, stagePool); + // Create sidecar MSAA texture for the depth attachment if it does not already + // exist. + auto msaa = initMsaaTexture(depthTexture, device, physicalDevice, context, + allocator, commands, resourceManager, msLevel, samples, stagePool); mInfo->msaaDepthIndex = (uint8_t) attachments.size(); attachments.push_back({ .texture = msaa, .layerCount = layerCount }); - mResources.acquire(msaa); } } } @@ -491,9 +484,7 @@ void VulkanRenderTarget::emitBarriersEndRenderPass(VulkanCommandBuffer& commands VulkanVertexBufferInfo::VulkanVertexBufferInfo( uint8_t bufferCount, uint8_t attributeCount, AttributeArray const& attributes) : HwVertexBufferInfo(bufferCount, attributeCount), - VulkanResource(VulkanResourceType::VERTEX_BUFFER_INFO), mInfo(attributes.size()) { - auto attribDesc = mInfo.mSoa.data(); auto bufferDesc = mInfo.mSoa.data(); auto offsets = mInfo.mSoa.data(); @@ -531,19 +522,15 @@ VulkanVertexBufferInfo::VulkanVertexBufferInfo( } VulkanVertexBuffer::VulkanVertexBuffer(VulkanContext& context, VulkanStagePool& stagePool, - VulkanResourceAllocator* allocator, - uint32_t vertexCount, Handle vbih) + uint32_t vertexCount, fvkmemory::resource_ptr vbi) : HwVertexBuffer(vertexCount), - VulkanResource(VulkanResourceType::VERTEX_BUFFER), - vbih(vbih), - mBuffers(MAX_VERTEX_BUFFER_COUNT), // TODO: can we do better here? - mResources(allocator) { + vbi(vbi), + // TODO: Seems a bit wasteful. can we do better here? + mBuffers(MAX_VERTEX_BUFFER_COUNT) { } -void VulkanVertexBuffer::setBuffer(VulkanResourceAllocator const& allocator, - VulkanBufferObject* bufferObject, uint32_t index) { - VulkanVertexBufferInfo const* const vbi = - const_cast(allocator).handle_cast(vbih); +void VulkanVertexBuffer::setBuffer(fvkmemory::resource_ptr bufferObject, + uint32_t index) { size_t const count = vbi->getAttributeCount(); VkBuffer* const vkbuffers = getVkBuffers(); int8_t const* const attribToBuffer = vbi->getAttributeToBuffer(); @@ -552,25 +539,20 @@ void VulkanVertexBuffer::setBuffer(VulkanResourceAllocator const& allocator, vkbuffers[attribIndex] = bufferObject->buffer.getGpuBuffer(); } } - mResources.acquire(bufferObject); + mResources.push_back(bufferObject); } VulkanBufferObject::VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, uint32_t byteCount, BufferObjectBinding bindingType) : HwBufferObject(byteCount), - VulkanResource(VulkanResourceType::BUFFER_OBJECT), buffer(allocator, stagePool, getBufferObjectUsage(bindingType), byteCount), bindingType(bindingType) {} -VulkanRenderPrimitive::VulkanRenderPrimitive(VulkanResourceAllocator* resourceAllocator, - PrimitiveType pt, Handle vbh, Handle ibh) - : VulkanResource(VulkanResourceType::RENDER_PRIMITIVE), - mResources(resourceAllocator) { - type = pt; - vertexBuffer = resourceAllocator->handle_cast(vbh); - indexBuffer = resourceAllocator->handle_cast(ibh); - mResources.acquire(vertexBuffer); - mResources.acquire(indexBuffer); -} +VulkanRenderPrimitive::VulkanRenderPrimitive(PrimitiveType pt, + fvkmemory::resource_ptr vb, + fvkmemory::resource_ptr ib) + : HwRenderPrimitive{.type = pt}, + vertexBuffer(vb), + indexBuffer(ib) {} } // namespace filament::backend diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h index 1dc3141fd5a7..325098522835 100644 --- a/filament/backend/src/vulkan/VulkanHandles.h +++ b/filament/backend/src/vulkan/VulkanHandles.h @@ -20,14 +20,14 @@ // This needs to be at the top #include "DriverBase.h" +#include "VulkanAsyncHandles.h" #include "VulkanBuffer.h" #include "VulkanFboCache.h" -#include "VulkanResources.h" #include "VulkanSwapChain.h" #include "VulkanTexture.h" #include "VulkanUtility.h" +#include "vulkan/memory/Resource.h" -#include #include #include @@ -35,6 +35,8 @@ #include #include +#include + namespace filament::backend { namespace { @@ -55,7 +57,7 @@ inline uint8_t collapsedCount(Bitmask const& mask) { class VulkanTimestamps; struct VulkanBufferObject; -struct VulkanDescriptorSetLayout : public VulkanResource, HwDescriptorSetLayout { +struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Resource { static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT = 4; static constexpr uint8_t MAX_BINDINGS = 25; @@ -129,21 +131,19 @@ struct VulkanDescriptorSetLayout : public VulkanResource, HwDescriptorSetLayout VkDescriptorSetLayout mVkLayout = VK_NULL_HANDLE; }; -struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet { +struct VulkanDescriptorSet : public HwDescriptorSet, fvkmemory::Resource { public: // Because we need to recycle descriptor sets not used, we allow for a callback that the "Pool" // can use to repackage the vk handle. using OnRecycle = std::function; - VulkanDescriptorSet(VulkanResourceAllocator* allocator, VkDescriptorSet rawSet, + VulkanDescriptorSet(VkDescriptorSet rawSet, UniformBufferBitmask const& dynamicUboMask, uint8_t uniqueDynamicUboCount, OnRecycle&& onRecycleFn) - : VulkanResource(VulkanResourceType::DESCRIPTOR_SET), - vkSet(rawSet), + : vkSet(rawSet), dynamicUboMask(dynamicUboMask), uniqueDynamicUboCount(uniqueDynamicUboCount), - mResources(allocator), mOnRecycleFn(std::move(onRecycleFn)) {} ~VulkanDescriptorSet() { @@ -160,9 +160,8 @@ struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet { return &mOffsets; } - void acquire(VulkanTexture* texture); - - void acquire(VulkanBufferObject* texture); + void acquire(fvkmemory::resource_ptr texture); + void acquire(fvkmemory::resource_ptr buffer); VkDescriptorSet const vkSet; UniformBufferBitmask const dynamicUboMask; @@ -170,7 +169,7 @@ struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet { private: backend::DescriptorSetOffsetArray mOffsets; - VulkanAcquireOnlyResourceManager mResources; + std::vector> mResources; OnRecycle mOnRecycleFn; }; @@ -178,14 +177,11 @@ using PushConstantNameArray = utils::FixedCapacityVector; using PushConstantNameByStage = std::array; struct PushConstantDescription { - explicit PushConstantDescription(backend::Program const& program) noexcept; VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; } - uint32_t getVkRangeCount() const noexcept { return mRangeCount; } - - void write(VulkanCommands* commands, VkPipelineLayout layout, backend::ShaderStage stage, + void write(VkCommandBuffer cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value); private: @@ -196,12 +192,10 @@ struct PushConstantDescription { uint32_t mRangeCount; }; -struct VulkanProgram : public HwProgram, VulkanResource { - +struct VulkanProgram : public HwProgram, fvkmemory::Resource { using BindingList = CappedArray; VulkanProgram(VkDevice device, Program const& builder) noexcept; - ~VulkanProgram(); inline VkShaderModule getVertexShader() const { @@ -218,9 +212,9 @@ struct VulkanProgram : public HwProgram, VulkanResource { return mInfo->pushConstantDescription.getVkRanges(); } - inline void writePushConstant(VulkanCommands* commands, VkPipelineLayout layout, + inline void writePushConstant(VkCommandBuffer cmdbuf, VkPipelineLayout layout, backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) { - mInfo->pushConstantDescription.write(commands, layout, stage, index, value); + mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value); } #if FVK_ENABLED_DEBUG_SAMPLER_NAME @@ -255,16 +249,16 @@ struct VulkanProgram : public HwProgram, VulkanResource { // // We use private inheritance to shield clients from the width / height fields in HwRenderTarget, // which are not representative when this is the default render target. -struct VulkanRenderTarget : private HwRenderTarget, VulkanResource { +struct VulkanRenderTarget : private HwRenderTarget, fvkmemory::Resource { // Creates an offscreen render target. VulkanRenderTarget(VkDevice device, VkPhysicalDevice physicalDevice, - VulkanContext const& context, VmaAllocator allocator, - VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - uint32_t width, uint32_t height, + VulkanContext const& context, fvkmemory::ResourceManager* resourceManager, + VmaAllocator allocator, VulkanCommands* commands, uint32_t width, uint32_t height, uint8_t samples, VulkanAttachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT], VulkanAttachment depthStencil[2], VulkanStagePool& stagePool, uint8_t layerCount); + ~VulkanRenderTarget(); + // Creates a special "default" render target (i.e. associated with the swap chain) explicit VulkanRenderTarget(); @@ -276,12 +270,12 @@ struct VulkanRenderTarget : private HwRenderTarget, VulkanResource { return {width, height}; } - inline VulkanAttachment const& getColor0() const { + inline VulkanAttachment& getColor0() const { assert_invariant(mInfo->colors[0]); return mInfo->attachments[0]; } - inline VulkanAttachment const& getDepth() const { + inline VulkanAttachment& getDepth() const { assert_invariant(hasDepth()); if (mInfo->fbkey.samples == 1) { return mInfo->attachments[mInfo->depthIndex]; @@ -308,7 +302,7 @@ struct VulkanRenderTarget : private HwRenderTarget, VulkanResource { inline bool isSwapChain() const { return !mOffscreen; } inline bool isProtected() const { return mProtected; } - void bindToSwapChain(VulkanSwapChain& surf); + void bindToSwapChain(fvkmemory::resource_ptr swapchain); void emitBarriersBeginRenderPass(VulkanCommandBuffer& commands); @@ -331,13 +325,12 @@ struct VulkanRenderTarget : private HwRenderTarget, VulkanResource { bool const mOffscreen; bool mProtected; - VulkanAcquireOnlyResourceManager mResources; std::unique_ptr mInfo; }; struct VulkanBufferObject; -struct VulkanVertexBufferInfo : public HwVertexBufferInfo, VulkanResource { +struct VulkanVertexBufferInfo : public HwVertexBufferInfo, fvkmemory::Resource { VulkanVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount, AttributeArray const& attributes); @@ -384,33 +377,24 @@ struct VulkanVertexBufferInfo : public HwVertexBufferInfo, VulkanResource { PipelineInfo mInfo; }; -struct VulkanVertexBuffer : public HwVertexBuffer, VulkanResource { - VulkanVertexBuffer(VulkanContext& context, VulkanStagePool& stagePool, - VulkanResourceAllocator* allocator, - uint32_t vertexCount, Handle vbih); - - void setBuffer(VulkanResourceAllocator const& allocator, - VulkanBufferObject* bufferObject, uint32_t index); +struct VulkanVertexBuffer : public HwVertexBuffer, fvkmemory::Resource { + VulkanVertexBuffer(VulkanContext& context, VulkanStagePool& stagePool, uint32_t vertexCount, + fvkmemory::resource_ptr vbi); + void setBuffer(fvkmemory::resource_ptr bufferObject, uint32_t index); - inline VkBuffer const* getVkBuffers() const { - return mBuffers.data(); - } - - inline VkBuffer* getVkBuffers() { - return mBuffers.data(); - } + inline VkBuffer const* getVkBuffers() const { return mBuffers.data(); } + inline VkBuffer* getVkBuffers() { return mBuffers.data(); } + fvkmemory::resource_ptr vbi; - Handle vbih; private: utils::FixedCapacityVector mBuffers; - FixedSizeVulkanResourceManager mResources; + std::vector> mResources; }; -struct VulkanIndexBuffer : public HwIndexBuffer, VulkanResource { +struct VulkanIndexBuffer : public HwIndexBuffer, fvkmemory::Resource { VulkanIndexBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, uint8_t elementSize, uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount), - VulkanResource(VulkanResourceType::INDEX_BUFFER), buffer(allocator, stagePool, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount), indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32) {} @@ -418,7 +402,7 @@ struct VulkanIndexBuffer : public HwIndexBuffer, VulkanResource { const VkIndexType indexType; }; -struct VulkanBufferObject : public HwBufferObject, VulkanResource { +struct VulkanBufferObject : public HwBufferObject, fvkmemory::Resource { VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, uint32_t byteCount, BufferObjectBinding bindingType); @@ -426,28 +410,13 @@ struct VulkanBufferObject : public HwBufferObject, VulkanResource { const BufferObjectBinding bindingType; }; -struct VulkanSamplerGroup : public HwSamplerGroup, VulkanResource { - // NOTE: we have to use out-of-line allocation here because the size of a Handle<> is limited - std::unique_ptr sb;// FIXME: this shouldn't depend on filament::SamplerGroup - explicit VulkanSamplerGroup(size_t size) noexcept - : VulkanResource(VulkanResourceType::SAMPLER_GROUP), - sb(new SamplerGroup(size)) {} -}; - -struct VulkanRenderPrimitive : public HwRenderPrimitive, VulkanResource { - VulkanRenderPrimitive(VulkanResourceAllocator* resourceAllocator, - PrimitiveType pt, Handle vbh, Handle ibh); +struct VulkanRenderPrimitive : public HwRenderPrimitive, fvkmemory::Resource { + VulkanRenderPrimitive(PrimitiveType pt, fvkmemory::resource_ptr vb, + fvkmemory::resource_ptr ib); + ~VulkanRenderPrimitive() = default; - ~VulkanRenderPrimitive() { - mResources.clear(); - } - - VulkanVertexBuffer* vertexBuffer = nullptr; - VulkanIndexBuffer* indexBuffer = nullptr; - -private: - // Keep references to the vertex buffer and the index buffer. - FixedSizeVulkanResourceManager<2> mResources; + fvkmemory::resource_ptr vertexBuffer; + fvkmemory::resource_ptr indexBuffer; }; inline constexpr VkBufferUsageFlagBits getBufferObjectUsage( diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index dd730fdab739..4cf98cef15a7 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -241,7 +241,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value(); } -void VulkanPipelineCache::bindProgram(VulkanProgram* program) noexcept { +void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr program) noexcept { mPipelineRequirements.shaders[0] = program->getVertexShader(); mPipelineRequirements.shaders[1] = program->getFragmentShader(); diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index 702d27f245ff..c0500fbb8be9 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -19,7 +19,6 @@ #include "VulkanCommands.h" #include "VulkanMemory.h" -#include "VulkanResources.h" #include "VulkanUtility.h" #include @@ -44,7 +43,6 @@ namespace filament::backend { struct VulkanProgram; struct VulkanBufferObject; struct VulkanTexture; -class VulkanResourceAllocator; // VulkanPipelineCache manages a cache of descriptor sets and pipelines. // @@ -122,7 +120,7 @@ class VulkanPipelineCache { void bindPipeline(VulkanCommandBuffer* commands); // Each of the following methods are fast and do not make Vulkan calls. - void bindProgram(VulkanProgram* program) noexcept; + void bindProgram(fvkmemory::resource_ptr program) noexcept; void bindRasterState(const RasterState& rasterState) noexcept; void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept; void bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept; diff --git a/filament/backend/src/vulkan/VulkanReadPixels.cpp b/filament/backend/src/vulkan/VulkanReadPixels.cpp index c7d95d96bec0..48df6c722276 100644 --- a/filament/backend/src/vulkan/VulkanReadPixels.cpp +++ b/filament/backend/src/vulkan/VulkanReadPixels.cpp @@ -117,9 +117,10 @@ void VulkanReadPixels::terminate() noexcept { VulkanReadPixels::VulkanReadPixels(VkDevice device) : mDevice(device) {} -void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint32_t const y, - uint32_t const width, uint32_t const height, uint32_t const graphicsQueueFamilyIndex, - PixelBufferDescriptor&& pbd, SelecteMemoryFunction const& selectMemoryFunc, +void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget, uint32_t const x, + uint32_t const y, uint32_t const width, uint32_t const height, + uint32_t const graphicsQueueFamilyIndex, PixelBufferDescriptor&& pbd, + SelecteMemoryFunction const& selectMemoryFunc, OnReadCompleteFunction const& readCompleteFunc) { assert_invariant(mDevice != VK_NULL_HANDLE); @@ -143,7 +144,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint VkCommandPool& cmdpool = mCommandPool; - VulkanTexture* srcTexture = srcTarget->getColor0().texture; + fvkmemory::resource_ptr srcTexture = srcTarget->getColor0().texture; assert_invariant(srcTexture); VkFormat const srcFormat = srcTexture->getVkFormat(); bool const swizzle diff --git a/filament/backend/src/vulkan/VulkanReadPixels.h b/filament/backend/src/vulkan/VulkanReadPixels.h index e5dd2a31bb9f..23699537d316 100644 --- a/filament/backend/src/vulkan/VulkanReadPixels.h +++ b/filament/backend/src/vulkan/VulkanReadPixels.h @@ -17,6 +17,7 @@ #ifndef TNT_FILAMENT_BACKEND_VULKANREADPIXELS_H #define TNT_FILAMENT_BACKEND_VULKANREADPIXELS_H +#include "vulkan/memory/ResourcePointer.h" #include "private/backend/Driver.h" #include @@ -72,9 +73,9 @@ class VulkanReadPixels { void terminate() noexcept; - void run(VulkanRenderTarget* srcTarget, uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t graphicsQueueFamilyIndex, PixelBufferDescriptor&& pbd, - SelecteMemoryFunction const& selectMemoryFunc, + void run(fvkmemory::resource_ptr srcTarget, uint32_t x, uint32_t y, + uint32_t width, uint32_t height, uint32_t graphicsQueueFamilyIndex, + PixelBufferDescriptor&& pbd, SelecteMemoryFunction const& selectMemoryFunc, OnReadCompleteFunction const& readCompleteFunc); // This method will block until all of the in-flight requests are complete. diff --git a/filament/backend/src/vulkan/VulkanResourceAllocator.h b/filament/backend/src/vulkan/VulkanResourceAllocator.h deleted file mode 100644 index 572aeed4f78a..000000000000 --- a/filament/backend/src/vulkan/VulkanResourceAllocator.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2023 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. - */ - -#ifndef TNT_FILAMENT_BACKEND_VULKANRESOURCEALLOCATOR_H -#define TNT_FILAMENT_BACKEND_VULKANRESOURCEALLOCATOR_H - -#include "VulkanConstants.h" -#include "VulkanHandles.h" - -#include - -#include -#include - -#include -#include - -namespace filament::backend { - -#define RESOURCE_TYPE_COUNT (static_cast(VulkanResourceType::END_TYPE)) -#define DEBUG_RESOURCE_LEAKS FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) - -#if DEBUG_RESOURCE_LEAKS - #define TRACK_INCREMENT() \ - if (!IS_HEAP_ALLOC_TYPE(obj->getType())) { \ - mDebugOnlyResourceCount[static_cast(obj->getType())]++; \ - } - #define TRACK_DECREMENT() \ - if (!IS_HEAP_ALLOC_TYPE(obj->getType())) { \ - mDebugOnlyResourceCount[static_cast(obj->getType())]--; \ - } -#else - // No-op - #define TRACK_INCREMENT() - #define TRACK_DECREMENT() -#endif - -class VulkanResourceAllocator { -public: - using AllocatorImpl = HandleAllocatorVK; - VulkanResourceAllocator(size_t arenaSize, bool disableUseAfterFreeCheck) - : mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck) -#if DEBUG_RESOURCE_LEAKS - , mDebugOnlyResourceCount(RESOURCE_TYPE_COUNT) { - std::memset(mDebugOnlyResourceCount.data(), 0, sizeof(size_t) * RESOURCE_TYPE_COUNT); - } -#else - {} -#endif - - template - inline Handle initHandle(ARGS&&... args) noexcept { - auto handle = mHandleAllocatorImpl.allocateAndConstruct(std::forward(args)...); - auto obj = handle_cast(handle); - obj->initResource(handle.getId()); - TRACK_INCREMENT(); - return handle; - } - - template - inline Handle allocHandle() noexcept { - return mHandleAllocatorImpl.allocate(); - } - - template - inline typename std::enable_if::value, D>::type* construct( - Handle const& handle, ARGS&&... args) noexcept { - auto obj = mHandleAllocatorImpl.construct(handle, std::forward(args)...); - obj->initResource(handle.getId()); - TRACK_INCREMENT(); - return obj; - } - - template - inline typename std::enable_if_t< - std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle& handle) noexcept { - return mHandleAllocatorImpl.handle_cast(handle); - } - - template - inline typename std::enable_if_t< - std::is_pointer_v && std::is_base_of_v>, Dp> - handle_cast(Handle const& handle) noexcept { - return mHandleAllocatorImpl.handle_cast(handle); - } - - template - inline void destruct(Handle handle) noexcept { - auto obj = handle_cast(handle); - TRACK_DECREMENT(); - mHandleAllocatorImpl.deallocate(handle, obj); - } - - inline void associateHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept { - mHandleAllocatorImpl.associateTagToHandle(id, std::move(tag)); - } - -private: - AllocatorImpl mHandleAllocatorImpl; - -#if DEBUG_RESOURCE_LEAKS -public: - void print() { - FVK_LOGD << "Resource Allocator state (debug only)" << utils::io::endl; - for (size_t i = 0; i < RESOURCE_TYPE_COUNT; i++) { - FVK_LOGD << "[" << i << "]=" << mDebugOnlyResourceCount[i] << utils::io::endl; - } - FVK_LOGD << "+++++++++++++++++++++++++++++++++++++" << utils::io::endl; - } -private: - utils::FixedCapacityVector mDebugOnlyResourceCount; -#endif - -}; - -#undef TRACK_INCREMENT -#undef TRACK_DECREMENT -#undef DEBUG_RESOURCE_LEAKS - -} // namespace filament::backend - -#endif // TNT_FILAMENT_BACKEND_VULKANRESOURCEALLOCATOR_H diff --git a/filament/backend/src/vulkan/VulkanResources.cpp b/filament/backend/src/vulkan/VulkanResources.cpp deleted file mode 100644 index deb3a3168e67..000000000000 --- a/filament/backend/src/vulkan/VulkanResources.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2023 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 "VulkanResources.h" -#include "VulkanHandles.h" -#include "VulkanResourceAllocator.h" -#include "VulkanPipelineCache.h" - -namespace filament::backend { - -void deallocateResource(VulkanResourceAllocator* allocator, VulkanResourceType type, - HandleBase::HandleId id) { - - if (IS_HEAP_ALLOC_TYPE(type)) { - return; - } - - switch (type) { - case VulkanResourceType::BUFFER_OBJECT: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::INDEX_BUFFER: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::PROGRAM: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::RENDER_TARGET: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::SAMPLER_GROUP: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::SWAP_CHAIN: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::TEXTURE: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::TIMER_QUERY: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::VERTEX_BUFFER_INFO: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::VERTEX_BUFFER: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::RENDER_PRIMITIVE: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::DESCRIPTOR_SET_LAYOUT: - allocator->destruct(Handle(id)); - break; - case VulkanResourceType::DESCRIPTOR_SET: - allocator->destruct(Handle(id)); - break; - - // If the resource is heap allocated, then the resource manager just skip refcounted - // destruction. - case VulkanResourceType::FENCE: - case VulkanResourceType::HEAP_ALLOCATED: - case VulkanResourceType::END_TYPE: - break; - } -} - -} // namespace filament::backend diff --git a/filament/backend/src/vulkan/VulkanResources.h b/filament/backend/src/vulkan/VulkanResources.h deleted file mode 100644 index cbfb70ab6081..000000000000 --- a/filament/backend/src/vulkan/VulkanResources.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2023 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. - */ - -#ifndef TNT_FILAMENT_BACKEND_VULKANRESOURCES_H -#define TNT_FILAMENT_BACKEND_VULKANRESOURCES_H - -#include "VulkanUtility.h" - -#include - -#include -#include -#include - -#include -#include - -namespace filament::backend { - -class VulkanResourceAllocator; -struct VulkanThreadSafeResource; - -// Subclasses of VulkanResource must provide this enum in their construction. -enum class VulkanResourceType : uint8_t { - BUFFER_OBJECT = 0, - INDEX_BUFFER = 1, - PROGRAM = 2, - RENDER_TARGET = 3, - SAMPLER_GROUP = 4, - SWAP_CHAIN = 5, - RENDER_PRIMITIVE = 6, - TEXTURE = 7, - TIMER_QUERY = 8, - VERTEX_BUFFER = 9, - VERTEX_BUFFER_INFO = 10, - DESCRIPTOR_SET_LAYOUT = 11, - DESCRIPTOR_SET = 12, - - // Below are resources that are managed manually (i.e. not ref counted). - FENCE = 13, - HEAP_ALLOCATED = 14, - - END_TYPE = 15, // A placeholder -}; - -#define IS_HEAP_ALLOC_TYPE(f) \ - (f == VulkanResourceType::FENCE || f == VulkanResourceType::HEAP_ALLOCATED) - - -// This is a ref-counting base class that tracks how many references of this resource exist. This -// class is paired with VulkanResourceManagerImpl which is responsible for incrementing or -// decrementing the count. Once mRefCount == 0, VulkanResourceManagerImpl will also call the -// appropriate destructor. VulkanCommandBuffer, VulkanDriver, and composite structure like -// VulkanRenderPrimitive are owners of VulkanResourceManagerImpl instances. -struct VulkanResourceBase { -protected: - explicit VulkanResourceBase(VulkanResourceType type) - : mRefCount(IS_HEAP_ALLOC_TYPE(type) ? 1 : 0), - mType(uint32_t(type)), - mHandleId(0) { - } - -private: - inline VulkanResourceType getType() const noexcept { - return VulkanResourceType(mType); - } - - inline HandleBase::HandleId getId() const noexcept { - return mHandleId; - } - - inline void initResource(HandleBase::HandleId id) noexcept { - mHandleId = id; - } - - inline void ref() noexcept { - if (IS_HEAP_ALLOC_TYPE(getType())) { - return; - } - assert_invariant(mRefCount < ((1<<24) - 1)); - ++mRefCount; - } - - inline void deref() noexcept { - if (IS_HEAP_ALLOC_TYPE(getType())) { - return; - } - assert_invariant(mRefCount > 0); - --mRefCount; - } - - inline size_t refcount() const noexcept { - return mRefCount; - } - - uint32_t mRefCount : 24; // 16M is enough for the refcount - uint32_t mType : 8; // must be uint32_t or MSVC doesn't pack it. no codegen impact w/ clang. - HandleBase::HandleId mHandleId; - - friend struct VulkanThreadSafeResource; - friend class VulkanResourceAllocator; - - template - friend class VulkanResourceManagerImpl; -}; - -static_assert(sizeof(VulkanResourceBase) == 8, "VulkanResourceBase should be 8 bytes"); - -struct VulkanThreadSafeResource { -protected: - explicit VulkanThreadSafeResource(VulkanResourceType type) - : mImpl(type) {} - -private: - inline VulkanResourceType getType() { - return mImpl.getType(); - } - - inline HandleBase::HandleId getId() { - return mImpl.getId(); - } - - inline void initResource(HandleBase::HandleId id) noexcept { - std::unique_lock lock(mMutex); - mImpl.initResource(id); - } - - inline void ref() noexcept { - std::unique_lock lock(mMutex); - mImpl.ref(); - } - - inline void deref() noexcept { - std::unique_lock lock(mMutex); - mImpl.deref(); - } - - inline size_t refcount() noexcept { - std::unique_lock lock(mMutex); - return mImpl.refcount(); - } - - utils::Mutex mMutex; - VulkanResourceBase mImpl; - - friend class VulkanResourceAllocator; - template - friend class VulkanResourceManagerImpl; -}; - -using VulkanResource = VulkanResourceBase; - -namespace { - -// When the size of the resource set is known to be small, (for example for VulkanRenderPrimitive), -// we just use a std::array to back the set. -template -using FixedCapacityResourceSet = CappedArray; - -// robin_set/map are useful for sets that are acquire only and the set will be iterated when the set -// is cleared. -using FastIterationResourceSet = tsl::robin_set; - -// unoredered_set is used in the general case where insert/erase can occur at will. This is useful -// for the basic object ownership count - i.e. VulkanDriver. -using ResourceSet = std::unordered_set; - -using ThreadSafeResourceSet = std::unordered_set; - -} // anonymous namespace - -class VulkanResourceAllocator; - -#define LOCK_IF_NEEDED() \ - if constexpr (std::is_base_of_v) { \ - mMutex->lock(); \ - } - -#define UNLOCK_IF_NEEDED() \ - if constexpr (std::is_base_of_v) { \ - mMutex->unlock(); \ - } - -void deallocateResource(VulkanResourceAllocator* allocator, VulkanResourceType type, - HandleBase::HandleId id); - -template -class VulkanResourceManagerImpl { -public: - explicit VulkanResourceManagerImpl(VulkanResourceAllocator* allocator) - : mAllocator(allocator) { - if constexpr (std::is_base_of_v) { - mMutex = std::make_unique(); - } - } - - VulkanResourceManagerImpl(const VulkanResourceManagerImpl& other) = delete; - void operator=(const VulkanResourceManagerImpl& other) = delete; - VulkanResourceManagerImpl(const VulkanResourceManagerImpl&& other) = delete; - void operator=(const VulkanResourceManagerImpl&& other) = delete; - - ~VulkanResourceManagerImpl() { - clear(); - } - - inline void acquire(ResourceType* resource) { - if (IS_HEAP_ALLOC_TYPE(resource->getType())) { - return; - } - - LOCK_IF_NEEDED(); - if (mResources.find(resource) != mResources.end()) { - UNLOCK_IF_NEEDED(); - return; - } - mResources.insert(resource); - UNLOCK_IF_NEEDED(); - resource->ref(); - } - - // Transfers ownership from one resource set to another - template - inline void acquireAll(VulkanResourceManagerImpl* srcResources) { - copyAll(srcResources); - srcResources->clear(); - } - - // Transfers ownership from one resource set to another - template - inline void copyAll(VulkanResourceManagerImpl* srcResources) { - LOCK_IF_NEEDED(); - for (auto iter = srcResources->mResources.begin(); iter != srcResources->mResources.end(); - iter++) { - acquire(*iter); - } - UNLOCK_IF_NEEDED(); - } - - inline void release(ResourceType* resource) { - if (IS_HEAP_ALLOC_TYPE(resource->getType())) { - return; - } - - LOCK_IF_NEEDED(); - auto resItr = mResources.find(resource); - if (resItr == mResources.end()) { - UNLOCK_IF_NEEDED(); - return; - } - mResources.erase(resItr); - UNLOCK_IF_NEEDED(); - derefImpl(resource); - } - - inline void clear() { - LOCK_IF_NEEDED(); - for (auto iter = mResources.begin(); iter != mResources.end(); iter++) { - derefImpl(*iter); - } - mResources.clear(); - UNLOCK_IF_NEEDED(); - } - - inline size_t size() { - return mResources.size(); - } - -private: - inline void derefImpl(ResourceType* resource) { - resource->deref(); - if (resource->refcount() != 0) { - return; - } - deallocateResource(mAllocator, resource->getType(), resource->getId()); - } - - VulkanResourceAllocator* mAllocator; - SetType mResources; - std::unique_ptr mMutex; - - template friend class VulkanResourceManagerImpl; -}; - -using VulkanAcquireOnlyResourceManager - = VulkanResourceManagerImpl; -using VulkanResourceManager = VulkanResourceManagerImpl; - -template -using FixedSizeVulkanResourceManager = - VulkanResourceManagerImpl>; - -using VulkanThreadSafeResourceManager - = VulkanResourceManagerImpl; - -#undef LOCK_IF_NEEDED -#undef UNLOCK_IF_NEEDED - -} // namespace filament::backend - -#endif // TNT_FILAMENT_BACKEND_VULKANRESOURCES_H diff --git a/filament/backend/src/vulkan/VulkanStagePool.cpp b/filament/backend/src/vulkan/VulkanStagePool.cpp index 067b16afd848..cae1e85d257f 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.cpp +++ b/filament/backend/src/vulkan/VulkanStagePool.cpp @@ -16,6 +16,7 @@ #include "VulkanStagePool.h" +#include "VulkanCommands.h" #include "VulkanConstants.h" #include "VulkanImageUtility.h" #include "VulkanMemory.h" @@ -37,6 +38,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) { if (iter != mFreeStages.end()) { auto stage = iter->second; mFreeStages.erase(iter); + stage->lastAccessed = mCurrentFrame; mUsedStages.insert(stage); return stage; } @@ -59,7 +61,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) { UTILS_UNUSED_IN_RELEASE VkResult result = vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo, &stage->buffer, &stage->memory, nullptr); -#if FVK_ENABLED(FVK_DEBUG_ALLOCATION) +#if FVK_ENABLED(FVK_DEBUG_STAGING_ALLOCATION) if (result != VK_SUCCESS) { FVK_LOGE << "Allocation error: " << result << utils::io::endl; } @@ -74,6 +76,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi for (auto image : mFreeImages) { if (image->format == vkformat && image->width == width && image->height == height) { mFreeImages.erase(image); + image->lastAccessed = mCurrentFrame; mUsedImages.insert(image); return image; } diff --git a/filament/backend/src/vulkan/VulkanStagePool.h b/filament/backend/src/vulkan/VulkanStagePool.h index d2aacae5013b..6c8e307ff3f2 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.h +++ b/filament/backend/src/vulkan/VulkanStagePool.h @@ -17,8 +17,7 @@ #ifndef TNT_FILAMENT_BACKEND_VULKANSTAGEPOOL_H #define TNT_FILAMENT_BACKEND_VULKANSTAGEPOOL_H -#include "VulkanCommands.h" -#include "VulkanContext.h" +#include "backend/DriverEnums.h" #include "VulkanMemory.h" #include @@ -26,6 +25,8 @@ namespace filament::backend { +class VulkanCommands; + // Immutable POD representing a shared CPU-GPU staging area. struct VulkanStage { VmaAllocation memory; diff --git a/filament/backend/src/vulkan/VulkanSwapChain.cpp b/filament/backend/src/vulkan/VulkanSwapChain.cpp index bf9fd353cd83..c1df76e76db8 100644 --- a/filament/backend/src/vulkan/VulkanSwapChain.cpp +++ b/filament/backend/src/vulkan/VulkanSwapChain.cpp @@ -15,6 +15,8 @@ */ #include "VulkanSwapChain.h" + +#include "VulkanCommands.h" #include "VulkanTexture.h" #include @@ -26,19 +28,18 @@ using namespace utils; namespace filament::backend { VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const& context, - VmaAllocator allocator, VulkanCommands* commands, VulkanResourceAllocator* handleAllocator, - VulkanStagePool& stagePool, - void* nativeWindow, uint64_t flags, VkExtent2D extent) - : VulkanResource(VulkanResourceType::SWAP_CHAIN), - mPlatform(platform), + fvkmemory::ResourceManager* resourceManager, VmaAllocator allocator, + VulkanCommands* commands, VulkanStagePool& stagePool, void* nativeWindow, uint64_t flags, + VkExtent2D extent) + : mPlatform(platform), + mResourceManager(resourceManager), mCommands(commands), mAllocator(allocator), - mHandleAllocator(handleAllocator), mStagePool(stagePool), mHeadless(extent.width != 0 && extent.height != 0 && !nativeWindow), mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize), mTransitionSwapChainImageLayoutForPresent( - platform->getCustomization().transitionSwapChainImageLayoutForPresent), + platform->getCustomization().transitionSwapChainImageLayoutForPresent), mAcquired(false), mIsFirstRenderPass(true) { swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent); @@ -53,6 +54,9 @@ VulkanSwapChain::~VulkanSwapChain() { mCommands->flush(); mCommands->wait(); + mColors = {}; + mDepth = {}; + mPlatform->destroy(swapChain); } @@ -70,13 +74,16 @@ void VulkanSwapChain::update() { colorUsage |= TextureUsage::PROTECTED; } for (auto const color: bundle.colors) { - mColors.push_back(std::make_unique(device, mAllocator, mCommands, mHandleAllocator, - color, bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, - colorUsage, mStagePool, true /* heap allocated */)); + auto colorTexture = fvkmemory::resource_ptr::construct(mResourceManager, + device, mAllocator, mResourceManager, mCommands, color, bundle.colorFormat, 1, + bundle.extent.width, bundle.extent.height, TextureUsage::COLOR_ATTACHMENT, + mStagePool); + mColors.push_back(colorTexture); } - mDepth = std::make_unique(device, mAllocator, mCommands, mHandleAllocator, - bundle.depth, bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, - depthUsage, mStagePool, true /* heap allocated */); + + mDepth = fvkmemory::resource_ptr::construct(mResourceManager, device, mAllocator, + mResourceManager, mCommands, bundle.depth, bundle.depthFormat, 1, bundle.extent.width, + bundle.extent.height, TextureUsage::DEPTH_ATTACHMENT, mStagePool); mExtent = bundle.extent; } @@ -95,7 +102,7 @@ void VulkanSwapChain::present() { } mCommands->flush(); - + // call the image ready wait function if (mExplicitImageReadyWait != nullptr) { mExplicitImageReadyWait(swapChain); @@ -135,7 +142,7 @@ void VulkanSwapChain::acquire(bool& resized) { VkResult const result = mPlatform->acquire(swapChain, &imageSyncData); mCurrentSwapIndex = imageSyncData.imageIndex; mExplicitImageReadyWait = imageSyncData.explicitImageReadyWait; - FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) + FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) << "Cannot acquire in swapchain."; if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) { mCommands->injectDependency(imageSyncData.imageReadySemaphore); diff --git a/filament/backend/src/vulkan/VulkanSwapChain.h b/filament/backend/src/vulkan/VulkanSwapChain.h index acb88c56b950..bf1c26945bbc 100644 --- a/filament/backend/src/vulkan/VulkanSwapChain.h +++ b/filament/backend/src/vulkan/VulkanSwapChain.h @@ -19,9 +19,9 @@ #include "DriverBase.h" -#include "VulkanCommands.h" #include "VulkanContext.h" -#include "VulkanResources.h" +#include "VulkanTexture.h" +#include "vulkan/memory/Resource.h" #include @@ -36,14 +36,14 @@ namespace filament::backend { struct VulkanHeadlessSwapChain; struct VulkanSurfaceSwapChain; -class VulkanResourceAllocator; +class VulkanCommands; // A wrapper around the platform implementation of swapchain. -struct VulkanSwapChain : public HwSwapChain, VulkanResource { - VulkanSwapChain(VulkanPlatform* platform, VulkanContext const& context, VmaAllocator allocator, - VulkanCommands* commands, VulkanResourceAllocator* handleAllocator, - VulkanStagePool& stagePool, - void* nativeWindow, uint64_t flags, VkExtent2D extent = {0, 0}); +struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource { + VulkanSwapChain(VulkanPlatform* platform, VulkanContext const& context, + fvkmemory::ResourceManager* resourceManager, VmaAllocator allocator, + VulkanCommands* commands, VulkanStagePool& stagePool, void* nativeWindow, + uint64_t flags, VkExtent2D extent = {0, 0}); ~VulkanSwapChain(); @@ -51,15 +51,15 @@ struct VulkanSwapChain : public HwSwapChain, VulkanResource { void acquire(bool& reized); - inline VulkanTexture* getCurrentColor() const noexcept { + fvkmemory::resource_ptr getCurrentColor() const noexcept { uint32_t const imageIndex = mCurrentSwapIndex; FILAMENT_CHECK_PRECONDITION( imageIndex != VulkanPlatform::ImageSyncData::INVALID_IMAGE_INDEX); - return mColors[imageIndex].get(); + return mColors[imageIndex]; } - inline VulkanTexture* getDepth() const noexcept { - return mDepth.get(); + inline fvkmemory::resource_ptr getDepth() const noexcept { + return mDepth; } inline bool isFirstRenderPass() const noexcept { @@ -83,9 +83,9 @@ struct VulkanSwapChain : public HwSwapChain, VulkanResource { void update(); VulkanPlatform* mPlatform; + fvkmemory::ResourceManager* mResourceManager; VulkanCommands* mCommands; VmaAllocator mAllocator; - VulkanResourceAllocator* const mHandleAllocator; VulkanStagePool& mStagePool; bool const mHeadless; bool const mFlushAndWaitOnResize; @@ -93,8 +93,8 @@ struct VulkanSwapChain : public HwSwapChain, VulkanResource { // We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout // transitions, which are useful here. - utils::FixedCapacityVector> mColors; - std::unique_ptr mDepth; + utils::FixedCapacityVector> mColors; + fvkmemory::resource_ptr mDepth; VkExtent2D mExtent; uint32_t mCurrentSwapIndex; std::function mExplicitImageReadyWait = nullptr; diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp index a526310118ef..105ae8072d49 100644 --- a/filament/backend/src/vulkan/VulkanTexture.cpp +++ b/filament/backend/src/vulkan/VulkanTexture.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ +#include "VulkanCommands.h" #include "VulkanMemory.h" -#include "VulkanResourceAllocator.h" #include "VulkanTexture.h" #include "VulkanUtility.h" +#include "vulkan/memory/ResourcePointer.h" #include #include @@ -149,8 +150,7 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator, VulkanCommands* commands, VulkanStagePool& stagePool, VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount, VulkanLayout defaultLayout, bool isProtected) - : VulkanResource(VulkanResourceType::HEAP_ALLOCATED), - mVkFormat(format), + : mVkFormat(format), mViewType(viewType), mFullViewRange{filament::backend::getImageAspect(format), 0, levels, 0, layerCount}, mDefaultLayout(defaultLayout), @@ -161,61 +161,42 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator, mCommands(commands), mIsTransientAttachment(false) {} -VulkanTextureState* VulkanTexture::getSharedState() { - VulkanTextureState* state = mAllocator->handle_cast(mState); - return state; -} - -VulkanTextureState const* VulkanTexture::getSharedState() const { - VulkanTextureState const* state = mAllocator->handle_cast(mState); - return state; -} - // Constructor for internally passed VkImage -VulkanTexture::VulkanTexture( - VkDevice device, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - VkImage image, VkFormat format, uint8_t samples, uint32_t width, uint32_t height, - TextureUsage tusage, VulkanStagePool& stagePool, bool heapAllocated) - : HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED, - tusage), - VulkanResource( - heapAllocated ? VulkanResourceType::HEAP_ALLOCATED : VulkanResourceType::TEXTURE), - mAllocator(handleAllocator), - mState(handleAllocator->initHandle( - device, allocator, commands, stagePool, - format, imgutil::getViewType(SamplerType::SAMPLER_2D), 1, 1, - getDefaultLayoutImpl(tusage), - any(usage& TextureUsage::PROTECTED))) { - auto* const state = getSharedState(); - state->mTextureImage = image; - mPrimaryViewRange = state->mFullViewRange; +VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator, + fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image, + 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::construct(resourceManager, device, + allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D), + 1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) { + mState->mTextureImage = image; + mPrimaryViewRange = mState->mFullViewRange; } // Constructor for user facing texture VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, - VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, SamplerType target, uint8_t levels, - TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, - TextureUsage tusage, VulkanStagePool& stagePool, bool heapAllocated) + VulkanContext const& context, VmaAllocator allocator, + fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, SamplerType target, + uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, + uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool) : HwTexture(target, levels, samples, w, h, depth, tformat, tusage), - VulkanResource( - heapAllocated ? VulkanResourceType::HEAP_ALLOCATED : VulkanResourceType::TEXTURE), - mAllocator(handleAllocator), - mState(handleAllocator->initHandle(device, allocator, commands, stagePool, - backend::getVkFormat(tformat), imgutil::getViewType(target), levels, - getLayerCount(target, depth), VulkanLayout::UNDEFINED, any(usage& TextureUsage::PROTECTED))) { - auto* const state = getSharedState(); - + mState(fvkmemory::resource_ptr::construct(resourceManager, device, + allocator, commands, stagePool, backend::getVkFormat(tformat), + imgutil::getViewType(target), levels, getLayerCount(target, depth), + VulkanLayout::UNDEFINED, any(usage & TextureUsage::PROTECTED))) { // Create an appropriately-sized device-only VkImage, but do not fill it yet. - VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = target == SamplerType::SAMPLER_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D, - .format = state->mVkFormat, - .extent = {w, h, depth}, - .mipLevels = levels, - .arrayLayers = 1, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = 0}; + VkImageCreateInfo imageInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = target == SamplerType::SAMPLER_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D, + .format = mState->mVkFormat, + .extent = {w, h, depth}, + .mipLevels = levels, + .arrayLayers = 1, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = 0, + }; if (target == SamplerType::SAMPLER_CUBEMAP) { imageInfo.arrayLayers = 6; imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; @@ -254,7 +235,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, none(tusage & ~TextureUsage::ALL_ATTACHMENTS) && // Usage contains at least one attachment flag. any(tusage & TextureUsage::ALL_ATTACHMENTS); - state->mIsTransientAttachment = useTransientAttachment; + mState->mIsTransientAttachment = useTransientAttachment; const VkImageUsageFlags transientFlag = useTransientAttachment ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0U; @@ -299,7 +280,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, // any kind of attachment (color or depth). const auto& limits = context.getPhysicalDeviceLimits(); if (imageInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) { - samples = reduceSampleCount(samples, isVkDepthFormat(state->mVkFormat) + samples = reduceSampleCount(samples, isVkDepthFormat(mState->mVkFormat) ? limits.sampledImageDepthSampleCounts : limits.sampledImageColorSampleCounts); } @@ -313,12 +294,12 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, this->samples = samples; imageInfo.samples = (VkSampleCountFlagBits) samples; - VkResult error = vkCreateImage(state->mDevice, &imageInfo, VKALLOC, &state->mTextureImage); + VkResult error = vkCreateImage(mState->mDevice, &imageInfo, VKALLOC, &mState->mTextureImage); if (error || FVK_ENABLED(FVK_DEBUG_TEXTURE)) { FVK_LOGD << "vkCreateImage: " - << "image = " << state->mTextureImage << ", " + << "image = " << mState->mTextureImage << ", " << "result = " << error << ", " - << "handle = " << utils::io::hex << state->mTextureImage << utils::io::dec << ", " + << "handle = " << utils::io::hex << mState->mTextureImage << utils::io::dec << ", " << "extent = " << w << "x" << h << "x"<< depth << ", " << "mipLevels = " << int(levels) << ", " << "TextureUsage = " << static_cast(usage) << ", " @@ -327,18 +308,18 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, << "type = " << imageInfo.imageType << ", " << "flags = " << imageInfo.flags << ", " << "target = " << static_cast(target) <<", " - << "format = " << state->mVkFormat << utils::io::endl; + << "format = " << mState->mVkFormat << utils::io::endl; } FILAMENT_CHECK_POSTCONDITION(!error) << "Unable to create image."; // Allocate memory for the VkImage and bind it. VkMemoryRequirements memReqs = {}; - vkGetImageMemoryRequirements(state->mDevice, state->mTextureImage, &memReqs); + vkGetImageMemoryRequirements(mState->mDevice, mState->mTextureImage, &memReqs); const VkFlags requiredMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | (useTransientAttachment ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0U) | - (state->mIsProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U); + (mState->mIsProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U); uint32_t memoryTypeIndex = context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags); @@ -350,37 +331,29 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, .allocationSize = memReqs.size, .memoryTypeIndex = memoryTypeIndex, }; - error = vkAllocateMemory(state->mDevice, &allocInfo, nullptr, &state->mTextureImageMemory); + error = vkAllocateMemory(mState->mDevice, &allocInfo, nullptr, &mState->mTextureImageMemory); FILAMENT_CHECK_POSTCONDITION(!error) << "Unable to allocate image memory."; - error = vkBindImageMemory(state->mDevice, state->mTextureImage, state->mTextureImageMemory, 0); + error = vkBindImageMemory(mState->mDevice, mState->mTextureImage, mState->mTextureImageMemory, + 0); FILAMENT_CHECK_POSTCONDITION(!error) << "Unable to bind image."; // Spec out the "primary" VkImageView that shaders use to sample from the image. - mPrimaryViewRange = state->mFullViewRange; + mPrimaryViewRange = mState->mFullViewRange; // Go ahead and create the primary image view. - getImageView(mPrimaryViewRange, state->mViewType, mSwizzle); + getImageView(mPrimaryViewRange, mState->mViewType, mSwizzle); - VulkanCommandBuffer& commandsBuf = state->mCommands->get(); - commandsBuf.acquire(this); - - auto const defaultLayout = state->mDefaultLayout = getDefaultLayoutImpl(imageInfo.usage); - transitionLayout(&commandsBuf, mPrimaryViewRange, defaultLayout); + mState->mDefaultLayout = getDefaultLayoutImpl(imageInfo.usage); } // Constructor for creating a texture view VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, VulkanTexture const* src, uint8_t baseLevel, + fvkmemory::resource_ptr src, uint8_t baseLevel, uint8_t levelCount) : HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth, - src->format, src->usage), - VulkanResource(VulkanResourceType::TEXTURE), - mAllocator(handleAllocator) { + src->format, src->usage) { mState = src->mState; - auto* state = getSharedState(); - - state->refs++; mPrimaryViewRange = src->mPrimaryViewRange; mPrimaryViewRange.baseMipLevel = src->mPrimaryViewRange.baseMipLevel + baseLevel; mPrimaryViewRange.levelCount = levelCount; @@ -389,31 +362,21 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, // Constructor for creating a texture view with swizzle VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, VulkanTexture const* src, - VkComponentMapping swizzle) + fvkmemory::resource_ptr src, VkComponentMapping swizzle) : HwTexture(src->target, src->levels, src->samples, src->width, src->height, src->depth, - src->format, src->usage), - VulkanResource(VulkanResourceType::TEXTURE), - mAllocator(handleAllocator) { + src->format, src->usage) { mState = src->mState; - auto* state = getSharedState(); - state->refs++; mPrimaryViewRange = src->mPrimaryViewRange; mSwizzle = composeSwizzle(src->mSwizzle, swizzle); } -VulkanTexture::~VulkanTexture() { - auto* const state = getSharedState(); - state->refs--; - if (state->refs == 0) { - if (state->mTextureImageMemory != VK_NULL_HANDLE) { - vkDestroyImage(state->mDevice, state->mTextureImage, VKALLOC); - vkFreeMemory(state->mDevice, state->mTextureImageMemory, VKALLOC); - } - for (auto entry: state->mCachedImageViews) { - vkDestroyImageView(state->mDevice, entry.second, VKALLOC); - } - mAllocator->destruct(mState); +VulkanTextureState::~VulkanTextureState() { + if (mTextureImageMemory != VK_NULL_HANDLE) { + vkDestroyImage(mDevice, mTextureImage, VKALLOC); + vkFreeMemory(mDevice, mTextureImageMemory, VKALLOC); + } + for (auto entry: mCachedImageViews) { + vkDestroyImageView(mDevice, entry.second, VKALLOC); } } @@ -422,8 +385,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt assert_invariant(width <= this->width && height <= this->height); assert_invariant(depth <= this->depth * ((target == SamplerType::SAMPLER_CUBEMAP || target == SamplerType::SAMPLER_CUBEMAP_ARRAY) ? 6 : 1)); - auto* const state = getSharedState(); - assert_invariant(state->mIsProtected == false); + assert_invariant(!mState->mIsProtected); const PixelBufferDescriptor* hostData = &data; PixelBufferDescriptor reshapedData; @@ -436,7 +398,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt // If format conversion is both required and supported, use vkCmdBlitImage. const VkFormat hostFormat = backend::getVkFormat(hostData->format, hostData->type); - const VkFormat deviceFormat = getVkFormatLinear(state->mVkFormat); + const VkFormat deviceFormat = getVkFormatLinear(mState->mVkFormat); if (hostFormat != deviceFormat && hostFormat != VK_FORMAT_UNDEFINED) { assert_invariant(xoffset == 0 && yoffset == 0 && zoffset == 0 && "Offsets not yet supported when format conversion is required."); @@ -448,16 +410,16 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt // Otherwise, use vkCmdCopyBufferToImage. void* mapped = nullptr; - VulkanStage const* stage = state->mStagePool.acquireStage(hostData->size); + VulkanStage const* stage = mState->mStagePool.acquireStage(hostData->size); assert_invariant(stage->memory); - vmaMapMemory(state->mAllocator, stage->memory, &mapped); + vmaMapMemory(mState->mAllocator, stage->memory, &mapped); memcpy(mapped, hostData->buffer, hostData->size); - vmaUnmapMemory(state->mAllocator, stage->memory); - vmaFlushAllocation(state->mAllocator, stage->memory, 0, hostData->size); + vmaUnmapMemory(mState->mAllocator, stage->memory); + vmaFlushAllocation(mState->mAllocator, stage->memory, 0, hostData->size); - VulkanCommandBuffer& commands = state->mCommands->get(); + VulkanCommandBuffer& commands = mState->mCommands->get(); VkCommandBuffer const cmdbuf = commands.buffer(); - commands.acquire(this); + commands.acquire(fvkmemory::resource_ptr::cast(this)); VkBufferImageCopy copyRegion = { .bufferOffset = {}, @@ -503,25 +465,24 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt transitionLayout(&commands, transitionRange, newLayout); - vkCmdCopyBufferToImage(cmdbuf, stage->buffer, state->mTextureImage, newVkLayout, 1, ©Region); + vkCmdCopyBufferToImage(cmdbuf, stage->buffer, mState->mTextureImage, newVkLayout, 1, ©Region); transitionLayout(&commands, transitionRange, nextLayout); } void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, uint32_t width, uint32_t height, uint32_t depth, uint32_t miplevel) { - auto* const state = getSharedState(); void* mapped = nullptr; VulkanStageImage const* stage - = state->mStagePool.acquireImage(hostData.format, hostData.type, width, height); - vmaMapMemory(state->mAllocator, stage->memory, &mapped); + = mState->mStagePool.acquireImage(hostData.format, hostData.type, width, height); + vmaMapMemory(mState->mAllocator, stage->memory, &mapped); memcpy(mapped, hostData.buffer, hostData.size); - vmaUnmapMemory(state->mAllocator, stage->memory); - vmaFlushAllocation(state->mAllocator, stage->memory, 0, hostData.size); + vmaUnmapMemory(mState->mAllocator, stage->memory); + vmaFlushAllocation(mState->mAllocator, stage->memory, 0, hostData.size); - VulkanCommandBuffer& commands = state->mCommands->get(); + VulkanCommandBuffer& commands = mState->mCommands->get(); VkCommandBuffer const cmdbuf = commands.buffer(); - commands.acquire(this); + commands.acquire(fvkmemory::resource_ptr::cast(this)); // TODO: support blit-based format conversion for 3D images and cubemaps. const int layer = 0; @@ -544,14 +505,13 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u transitionLayout(&commands, range, newLayout); vkCmdBlitImage(cmdbuf, stage->image, imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - state->mTextureImage, imgutil::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); + mState->mTextureImage, imgutil::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); transitionLayout(&commands, range, oldLayout); } VulkanLayout VulkanTexture::getDefaultLayout() const { - auto* const state = getSharedState(); - return state->mDefaultLayout; + return mState->mDefaultLayout; } VkImageView VulkanTexture::getAttachmentView(VkImageSubresourceRange range) { @@ -570,42 +530,43 @@ VkImageView VulkanTexture::getViewForType(VkImageSubresourceRange const& range, VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range, VkImageViewType viewType, VkComponentMapping swizzle) { - auto* const state = getSharedState(); VulkanTextureState::ImageViewKey const key{ range, viewType, swizzle }; - auto iter = state->mCachedImageViews.find(key); - if (iter != state->mCachedImageViews.end()) { + auto iter = mState->mCachedImageViews.find(key); + if (iter != mState->mCachedImageViews.end()) { return iter->second; } VkImageViewCreateInfo viewInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, .flags = 0, - .image = state->mTextureImage, + .image = mState->mTextureImage, .viewType = viewType, - .format = state->mVkFormat, + .format = mState->mVkFormat, .components = swizzle, .subresourceRange = range, }; VkImageView imageView; - vkCreateImageView(state->mDevice, &viewInfo, VKALLOC, &imageView); - state->mCachedImageViews.emplace(key, imageView); + vkCreateImageView(mState->mDevice, &viewInfo, VKALLOC, &imageView); + mState->mCachedImageViews.emplace(key, imageView); return imageView; } VkImageAspectFlags VulkanTexture::getImageAspect() const { // Helper function in VulkanUtility - auto* const state = getSharedState(); - return filament::backend::getImageAspect(state->mVkFormat); + return filament::backend::getImageAspect(mState->mVkFormat); } bool VulkanTexture::transitionLayout(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range, VulkanLayout newLayout) { - return transitionLayout(commands->buffer(), range, newLayout); + if (transitionLayout(commands->buffer(), range, newLayout)) { + commands->acquire(fvkmemory::resource_ptr::cast(this)); + return true; + } + return false; } bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceRange const& range, VulkanLayout newLayout) { - auto* const state = getSharedState(); VulkanLayout const oldLayout = getLayout(range.baseArrayLayer, range.baseMipLevel); uint32_t const firstLayer = range.baseArrayLayer; @@ -636,7 +597,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR continue; } hasTransitions = hasTransitions || imgutil::transitionLayout(cmdbuf, { - .image = state->mTextureImage, + .image = mState->mTextureImage, .oldLayout = layout, .newLayout = newLayout, .subresources = { @@ -651,7 +612,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR } } else if (newLayout != oldLayout) { hasTransitions = imgutil::transitionLayout(cmdbuf, { - .image = state->mTextureImage, + .image = mState->mTextureImage, .oldLayout = oldLayout, .newLayout = newLayout, .subresources = range, @@ -684,7 +645,6 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); - auto* const state = getSharedState(); VkImageLayout const layout = imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { @@ -696,7 +656,7 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands, .newLayout = layout, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = state->mTextureImage, + .image = mState->mTextureImage, .subresourceRange = range, }; vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, @@ -708,7 +668,6 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands, void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); - auto* const state = getSharedState(); VkImageLayout const layout = imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { @@ -719,7 +678,7 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands, .newLayout = layout, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = state->mTextureImage, + .image = mState->mTextureImage, .subresourceRange = range, }; vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, @@ -727,7 +686,6 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands, } void VulkanTexture::setLayout(VkImageSubresourceRange const& range, VulkanLayout newLayout) { - auto* const state = getSharedState(); uint32_t const firstLayer = range.baseArrayLayer; uint32_t const lastLayer = firstLayer + range.layerCount; uint32_t const firstLevel = range.baseMipLevel; @@ -740,34 +698,32 @@ void VulkanTexture::setLayout(VkImageSubresourceRange const& range, VulkanLayout for (uint32_t layer = firstLayer; layer < lastLayer; ++layer) { uint32_t const first = (layer << 16) | firstLevel; uint32_t const last = (layer << 16) | lastLevel; - state->mSubresourceLayouts.clear(first, last); + mState->mSubresourceLayouts.clear(first, last); } } else { for (uint32_t layer = firstLayer; layer < lastLayer; ++layer) { uint32_t const first = (layer << 16) | firstLevel; uint32_t const last = (layer << 16) | lastLevel; - state->mSubresourceLayouts.add(first, last, newLayout); + mState->mSubresourceLayouts.add(first, last, newLayout); } } } VulkanLayout VulkanTexture::getLayout(uint32_t layer, uint32_t level) const { assert_invariant(level <= 0xffff && layer <= 0xffff); - auto* const state = getSharedState(); const uint32_t key = (layer << 16) | level; - if (!state->mSubresourceLayouts.has(key)) { + if (!mState->mSubresourceLayouts.has(key)) { return VulkanLayout::UNDEFINED; } - return state->mSubresourceLayouts.get(key); + return mState->mSubresourceLayouts.get(key); } #if FVK_ENABLED(FVK_DEBUG_TEXTURE) void VulkanTexture::print() const { - auto* const state = getSharedState(); uint32_t const firstLayer = 0; - uint32_t const lastLayer = firstLayer + state->mFullViewRange.layerCount; + uint32_t const lastLayer = firstLayer + mState->mFullViewRange.layerCount; uint32_t const firstLevel = 0; - uint32_t const lastLevel = firstLevel + state->mFullViewRange.levelCount; + uint32_t const lastLevel = firstLevel + mState->mFullViewRange.levelCount; for (uint32_t layer = firstLayer; layer < lastLayer; ++layer) { for (uint32_t level = firstLevel; level < lastLevel; ++level) { @@ -776,16 +732,16 @@ void VulkanTexture::print() const { layer < (mPrimaryViewRange.baseArrayLayer + mPrimaryViewRange.layerCount) && level >= mPrimaryViewRange.baseMipLevel && level < (mPrimaryViewRange.baseMipLevel + mPrimaryViewRange.levelCount); - FVK_LOGD << "[" << state->mTextureImage << "]: (" << layer << "," << level + FVK_LOGD << "[" << mState->mTextureImage << "]: (" << layer << "," << level << ")=" << getLayout(layer, level) << " primary=" << primary << utils::io::endl; } } - for (auto view: state->mCachedImageViews) { + for (auto view: mState->mCachedImageViews) { auto& range = view.first.range; - FVK_LOGD << "[" << state->mTextureImage << ", imageView=" << view.second << "]=>" + FVK_LOGD << "[" << mState->mTextureImage << ", imageView=" << view.second << "]=>" << " (" << range.baseArrayLayer << "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << "," << range.levelCount << ")" << " aspect=" << range.aspectMask << " viewType=" << view.first.type diff --git a/filament/backend/src/vulkan/VulkanTexture.h b/filament/backend/src/vulkan/VulkanTexture.h index 5165b1cec78a..e6f9e38ad400 100644 --- a/filament/backend/src/vulkan/VulkanTexture.h +++ b/filament/backend/src/vulkan/VulkanTexture.h @@ -20,8 +20,9 @@ #include "DriverBase.h" #include "VulkanBuffer.h" -#include "VulkanResources.h" #include "VulkanImageUtility.h" +#include "vulkan/memory/Resource.h" +#include "vulkan/memory/ResourcePointer.h" #include #include @@ -30,13 +31,13 @@ namespace filament::backend { -class VulkanResourceAllocator; - -struct VulkanTextureState : public VulkanResource { +struct VulkanTextureState : public fvkmemory::Resource { VulkanTextureState(VkDevice device, VmaAllocator allocator, VulkanCommands* commands, VulkanStagePool& stagePool, VkFormat format, VkImageViewType viewType, uint8_t levels, uint8_t layerCount, VulkanLayout defaultLayout, bool isProtected); + ~VulkanTextureState(); + struct ImageViewKey { VkImageSubresourceRange range; // 4 * 5 bytes VkImageViewType type; // 4 bytes @@ -58,10 +59,8 @@ struct VulkanTextureState : public VulkanResource { using ImageViewHash = utils::hash::MurmurHashFn; - uint32_t refs = 1; - // The texture with the sidecar owns the sidecar. - std::unique_ptr mSidecarMSAA; + fvkmemory::resource_ptr mSidecarMSAA; VkDeviceMemory mTextureImageMemory = VK_NULL_HANDLE; VkFormat const mVkFormat; @@ -83,37 +82,32 @@ struct VulkanTextureState : public VulkanResource { bool mIsTransientAttachment; }; - -struct VulkanTexture : public HwTexture, VulkanResource { +struct VulkanTexture : public HwTexture, fvkmemory::Resource { // Standard constructor for user-facing textures. VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, - VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - SamplerType target, uint8_t levels, - TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, - TextureUsage tusage, VulkanStagePool& stagePool, bool heapAllocated = false); + VmaAllocator allocator, fvkmemory::ResourceManager* resourceManager, + VulkanCommands* commands, SamplerType target, uint8_t levels, TextureFormat tformat, + uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, TextureUsage tusage, + VulkanStagePool& stagePool); // Specialized constructor for internally created textures (e.g. from a swap chain) // The texture will never destroy the given VkImage, but it does manages its subresources. - VulkanTexture(VkDevice device, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - VkImage image, + VulkanTexture(VkDevice device, VmaAllocator allocator, + fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image, VkFormat format, uint8_t samples, uint32_t width, uint32_t height, TextureUsage tusage, - VulkanStagePool& stagePool, bool heapAllocated = false); + VulkanStagePool& stagePool); // Constructor for creating a texture view for wrt specific mip range VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - VulkanTexture const* src, uint8_t baseLevel, uint8_t levelCount); + fvkmemory::resource_ptr src, uint8_t baseLevel, uint8_t levelCount); // Constructor for creating a texture view for swizzle. VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, - VulkanTexture const* src, VkComponentMapping swizzle); + fvkmemory::resource_ptr src, VkComponentMapping swizzle); - ~VulkanTexture(); + ~VulkanTexture() = default; // Uploads data into a subregion of a 2D or 3D texture. void updateImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height, @@ -121,16 +115,14 @@ struct VulkanTexture : public HwTexture, VulkanResource { // Returns the primary image view, which is used for shader sampling. VkImageView getPrimaryImageView() { - VulkanTextureState* state = getSharedState(); - return getImageView(mPrimaryViewRange, state->mViewType, mSwizzle); + return getImageView(mPrimaryViewRange, mState->mViewType, mSwizzle); } VkImageViewType getViewType() const { - VulkanTextureState const* state = getSharedState(); - return state->mViewType; + return mState->mViewType; } - VkImageSubresourceRange getPrimaryViewRange() const { return mPrimaryViewRange; } + VkImageSubresourceRange const& getPrimaryViewRange() const { return mPrimaryViewRange; } VulkanLayout getPrimaryImageLayout() const { return getLayout(mPrimaryViewRange.baseArrayLayer, mPrimaryViewRange.baseMipLevel); @@ -156,34 +148,28 @@ struct VulkanTexture : public HwTexture, VulkanResource { VkImageView getViewForType(VkImageSubresourceRange const& range, VkImageViewType type); VkFormat getVkFormat() const { - VulkanTextureState const* state = getSharedState(); - return state->mVkFormat; + return mState->mVkFormat; } VkImage getVkImage() const { - VulkanTextureState const* state = getSharedState(); - return state->mTextureImage; + return mState->mTextureImage; } VulkanLayout getLayout(uint32_t layer, uint32_t level) const; - void setSidecar(VulkanTexture* sidecar) { - VulkanTextureState* state = getSharedState(); - state->mSidecarMSAA.reset(sidecar); + void setSidecar(fvkmemory::resource_ptr sidecar) { + mState->mSidecarMSAA = sidecar; } - VulkanTexture* getSidecar() const { - VulkanTextureState const* state = getSharedState(); - return state->mSidecarMSAA.get(); + fvkmemory::resource_ptr getSidecar() const { + return mState->mSidecarMSAA; } bool isTransientAttachment() const { - VulkanTextureState const* state = getSharedState(); - return state->mIsTransientAttachment; + return mState->mIsTransientAttachment; } bool getIsProtected() const { - VulkanTextureState const* state = getSharedState(); - return state->mIsProtected; + return mState->mIsProtected; } bool transitionLayout(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range, @@ -211,9 +197,6 @@ struct VulkanTexture : public HwTexture, VulkanResource { #endif private: - VulkanTextureState* getSharedState(); - VulkanTextureState const* getSharedState() const; - // Gets or creates a cached VkImageView for a range of miplevels, array layers, viewType, and // swizzle (or not). VkImageView getImageView(VkImageSubresourceRange range, VkImageViewType viewType, @@ -222,9 +205,7 @@ struct VulkanTexture : public HwTexture, VulkanResource { void updateImageWithBlit(const PixelBufferDescriptor& hostData, uint32_t width, uint32_t height, uint32_t depth, uint32_t miplevel); - VulkanResourceAllocator* const mAllocator; - - Handle mState; + fvkmemory::resource_ptr mState; // Track the range of subresources that define the "primary" image view, which is the special // image view that gets bound to an actual texture sampler. diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp index 0533b58e0f4b..19aa989b8c01 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp @@ -16,11 +16,11 @@ #include "VulkanDescriptorSetManager.h" +#include #include #include #include #include -#include #include #include @@ -274,7 +274,7 @@ class VulkanDescriptorSetManager::DescriptorInfinitePool { DescriptorInfinitePool(VkDevice device) : mDevice(device) {} - VkDescriptorSet obtainSet(VulkanDescriptorSetLayout* layout) { + VkDescriptorSet obtainSet(fvkmemory::resource_ptr layout) { auto const vklayout = layout->getVkLayout(); DescriptorPool* sameTypePool = nullptr; for (auto& pool: mPools) { @@ -325,13 +325,12 @@ class VulkanDescriptorSetManager::DescriptorSetLayoutManager { DescriptorSetLayoutManager(VkDevice device) : mDevice(device) {} - VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout* layout) { - auto const& bitmasks = layout->bitmask; + VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks) { if (auto itr = mVkLayouts.find(bitmasks); itr != mVkLayouts.end()) { return itr->second; } - auto vklayout = createLayout(mDevice, layout->bitmask); - mVkLayouts[layout->bitmask] = vklayout; + auto vklayout = createLayout(mDevice, bitmasks); + mVkLayouts[bitmasks] = vklayout; return vklayout; } @@ -347,10 +346,11 @@ class VulkanDescriptorSetManager::DescriptorSetLayoutManager { mVkLayouts; }; + VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, - VulkanResourceAllocator* resourceAllocator) + fvkmemory::ResourceManager* resourceManager) : mDevice(device), - mResourceAllocator(resourceAllocator), + mResourceManager(resourceManager), mLayoutManager(std::make_unique(device)), mDescriptorPool(std::make_unique(device)) {} @@ -359,18 +359,20 @@ VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default; void VulkanDescriptorSetManager::terminate() noexcept{ mLayoutManager.reset(); mDescriptorPool.reset(); + clearHistory(); } // bind() is not really binding the set but just stashing until we have all the info // (pipelinelayout). -void VulkanDescriptorSetManager::bind(uint8_t setIndex, VulkanDescriptorSet* set, +void VulkanDescriptorSetManager::bind(uint8_t setIndex, + fvkmemory::resource_ptr set, backend::DescriptorSetOffsetArray&& offsets) { set->setOffsets(std::move(offsets)); mStashedSets[setIndex] = set; } void VulkanDescriptorSetManager::unbind(uint8_t setIndex) { - mStashedSets[setIndex] = nullptr; + mStashedSets[setIndex] = {}; } void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, @@ -412,14 +414,14 @@ void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, }; } -void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t binding, - VulkanBufferObject* bufferObject, VkDeviceSize offset, VkDeviceSize size) noexcept { +void VulkanDescriptorSetManager::updateBuffer(fvkmemory::resource_ptr set, + uint8_t binding, fvkmemory::resource_ptr bufferObject, + VkDeviceSize offset, VkDeviceSize size) noexcept { VkDescriptorBufferInfo const info = { .buffer = bufferObject->buffer.getGpuBuffer(), .offset = offset, .range = size, }; - VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; if (set->dynamicUboMask.test(binding)) { @@ -438,8 +440,9 @@ void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t set->acquire(bufferObject); } -void VulkanDescriptorSetManager::updateSampler(VulkanDescriptorSet* set, uint8_t binding, - VulkanTexture* texture, VkSampler sampler) noexcept { +void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptr set, + uint8_t binding, fvkmemory::resource_ptr texture, + VkSampler sampler) noexcept { VkDescriptorImageInfo info{ .sampler = sampler, }; @@ -469,38 +472,35 @@ void VulkanDescriptorSetManager::updateSampler(VulkanDescriptorSet* set, uint8_t set->acquire(texture); } -void VulkanDescriptorSetManager::updateInputAttachment(VulkanDescriptorSet* set, - VulkanAttachment attachment) noexcept { +void VulkanDescriptorSetManager::updateInputAttachment( + fvkmemory::resource_ptr set, + VulkanAttachment const& attachment) noexcept { // TOOD: fill-in this region } -void VulkanDescriptorSetManager::createSet(Handle handle, - VulkanDescriptorSetLayout* layout) { +fvkmemory::resource_ptr VulkanDescriptorSetManager::createSet( + Handle handle, fvkmemory::resource_ptr layout) { auto const vkSet = mDescriptorPool->obtainSet(layout); auto const& count = layout->count; auto const vklayout = layout->getVkLayout(); - mResourceAllocator->construct(handle, mResourceAllocator, vkSet, + return fvkmemory::resource_ptr::make(mResourceManager, handle, vkSet, layout->bitmask.dynamicUbo, layout->count.dynamicUbo, - [vkSet, count, vklayout, this](VulkanDescriptorSet* set) { - eraseSetFromHistory(set); - mDescriptorPool->recycle(count, vklayout, vkSet); + [vkSet, count, vklayout, this](VulkanDescriptorSet*) { + // Note that mDescriptorPool could be gone due to terminate (when the backend shuts + // down). + if (mDescriptorPool) { + mDescriptorPool->recycle(count, vklayout, vkSet); + } }); } -void VulkanDescriptorSetManager::destroySet(Handle handle) { -} - -void VulkanDescriptorSetManager::initVkLayout(VulkanDescriptorSetLayout* layout) { - layout->setVkLayout(mLayoutManager->getVkLayout(layout)); +void VulkanDescriptorSetManager::initVkLayout( + fvkmemory::resource_ptr layout) { + layout->setVkLayout(mLayoutManager->getVkLayout(layout->bitmask)); } -void VulkanDescriptorSetManager::eraseSetFromHistory(VulkanDescriptorSet* set) { - for (uint8_t i = 0; i < mStashedSets.size(); ++i) { - if (mStashedSets[i] == set) { - mStashedSets[i] = nullptr; - } - } +void VulkanDescriptorSetManager::clearHistory() { + mStashedSets = {}; } - } // namespace filament::backend diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h index 1bbf6e29b047..faeeb1442058 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h @@ -17,9 +17,10 @@ #ifndef TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H #define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H -#include -#include -#include +#include "vulkan/VulkanHandles.h" +#include "vulkan/VulkanTexture.h" +#include "vulkan/VulkanUtility.h" +#include "vulkan/memory/ResourcePointer.h" #include #include @@ -46,46 +47,45 @@ class VulkanDescriptorSetManager { using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray; - VulkanDescriptorSetManager(VkDevice device, VulkanResourceAllocator* resourceAllocator); + VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager); ~VulkanDescriptorSetManager(); void terminate() noexcept; - void updateBuffer(VulkanDescriptorSet* set, uint8_t binding, - VulkanBufferObject* bufferObject, VkDeviceSize offset, VkDeviceSize size) noexcept; + void updateBuffer(fvkmemory::resource_ptr set, uint8_t binding, + fvkmemory::resource_ptr bufferObject, VkDeviceSize offset, + VkDeviceSize size) noexcept; - void updateSampler(VulkanDescriptorSet* set, uint8_t binding, - VulkanTexture* texture, VkSampler sampler) noexcept; + void updateSampler(fvkmemory::resource_ptr set, uint8_t binding, + fvkmemory::resource_ptr texture, VkSampler sampler) noexcept; - void updateInputAttachment(VulkanDescriptorSet* set, VulkanAttachment attachment) noexcept; + void updateInputAttachment(fvkmemory::resource_ptr set, + VulkanAttachment const& attachment) noexcept; - void bind(uint8_t setIndex, VulkanDescriptorSet* set, backend::DescriptorSetOffsetArray&& offsets); + void bind(uint8_t setIndex, fvkmemory::resource_ptr set, + backend::DescriptorSetOffsetArray&& offsets); void unbind(uint8_t setIndex); void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask); - void setPlaceHolders(VkSampler sampler, VulkanTexture* texture, - VulkanBufferObject* bufferObject) noexcept; + fvkmemory::resource_ptr createSet(Handle handle, + fvkmemory::resource_ptr layout); - void createSet(Handle handle, VulkanDescriptorSetLayout* layout); + void initVkLayout(fvkmemory::resource_ptr layout); - void destroySet(Handle handle); - - void initVkLayout(VulkanDescriptorSetLayout* layout); + void clearHistory(); private: class DescriptorSetLayoutManager; class DescriptorInfinitePool; - void eraseSetFromHistory(VulkanDescriptorSet* set); - using DescriptorSetArray = - std::array; + std::array, UNIQUE_DESCRIPTOR_SET_COUNT>; VkDevice mDevice; - VulkanResourceAllocator* mResourceAllocator; + fvkmemory::ResourceManager* mResourceManager; std::unique_ptr mLayoutManager; std::unique_ptr mDescriptorPool; std::pair mInputAttachment; diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp index 09a84d33993f..256a616aa2e0 100644 --- a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp +++ b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp @@ -16,12 +16,11 @@ #include "VulkanPipelineLayoutCache.h" -#include - namespace filament::backend { VkPipelineLayout VulkanPipelineLayoutCache::getLayout( - DescriptorSetLayoutArray const& descriptorSetLayouts, VulkanProgram* program) { + DescriptorSetLayoutArray const& descriptorSetLayouts, + fvkmemory::resource_ptr program) { PipelineLayoutKey key = {}; uint8_t descSetLayoutCount = 0; key.descSetLayouts = descriptorSetLayouts; @@ -40,13 +39,13 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout( for (uint8_t i = 0; i < pushConstantRangeCount; ++i) { auto const& range = pushConstantRanges[i]; auto& pushConstant = key.pushConstant[i]; - if (range.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) { + if (range.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) { pushConstant.stage = static_cast(ShaderStage::VERTEX); } - if (range.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) { + if (range.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) { pushConstant.stage = static_cast(ShaderStage::FRAGMENT); } - if (range.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) { + if (range.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) { pushConstant.stage = static_cast(ShaderStage::COMPUTE); } pushConstant.size = range.size; diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h index 01d7122e2017..212ad60b0cf2 100644 --- a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h +++ b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h @@ -30,7 +30,7 @@ class VulkanPipelineLayoutCache { public: using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray; - VulkanPipelineLayoutCache(VkDevice device, VulkanResourceAllocator* allocator) + VulkanPipelineLayoutCache(VkDevice device) : mDevice(device), mTimestamp(0) {} @@ -56,7 +56,7 @@ class VulkanPipelineLayoutCache { // A pipeline layout depends on the descriptor set layout and the push constant ranges, which // are described in the program. VkPipelineLayout getLayout(DescriptorSetLayoutArray const& descriptorSetLayouts, - VulkanProgram* program); + fvkmemory::resource_ptr program); private: using Timestamp = uint64_t; diff --git a/filament/backend/src/vulkan/memory/ResourceManager.cpp b/filament/backend/src/vulkan/memory/ResourceManager.cpp index db938d61b9ff..0a64fd2562a8 100644 --- a/filament/backend/src/vulkan/memory/ResourceManager.cpp +++ b/filament/backend/src/vulkan/memory/ResourceManager.cpp @@ -22,7 +22,7 @@ namespace filament::backend::fvkmemory { namespace { -#if FVK_ENABLED(FVK_DEBUG_ALLOCATION) +#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) uint32_t COUNTER[(size_t) ResourceType::UNDEFINED_TYPE] = {}; #endif } @@ -47,8 +47,7 @@ void ResourceManager::gc() noexcept { } GcList gcs; - gcs.insert(gcs.end(), mGcList.begin(), mGcList.end()); - mGcList.clear(); + std::swap(gcs, mGcList); destroyAll(gcs); } @@ -105,20 +104,20 @@ void ResourceManager::destroyWithType(ResourceType type, HandleId id) { case ResourceType::UNDEFINED_TYPE: break; } -#if FVK_ENABLED(FVK_DEBUG_ALLOCATION) +#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) COUNTER[(size_t) type]--; #endif } void ResourceManager::traceConstruction(ResourceType type, HandleId id) { -#if FVK_ENABLED(FVK_DEBUG_ALLOCATION) +#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) assert_invariant(type != ResourceType::UNDEFINED_TYPE); COUNTER[(size_t) type]++; #endif } void ResourceManager::print() const noexcept { -#if FVK_ENABLED(FVK_DEBUG_ALLOCATION) +#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK) utils::slog.e << "-------------------" << utils::io::endl; for (size_t i = 0; i < (size_t) ResourceType::UNDEFINED_TYPE; ++i) { utils::slog.e <<" " << getTypeStr((ResourceType) i) << "=" << COUNTER[i] << utils::io::endl; diff --git a/filament/backend/src/vulkan/memory/ResourceManager.h b/filament/backend/src/vulkan/memory/ResourceManager.h index fa2b62da2604..fd2fef054bba 100644 --- a/filament/backend/src/vulkan/memory/ResourceManager.h +++ b/filament/backend/src/vulkan/memory/ResourceManager.h @@ -95,7 +95,6 @@ class ResourceManager { AllocatorImpl mHandleAllocatorImpl; using GcList = std::vector>; - utils::Mutex mThreadSafeGcListMutex; GcList mThreadSafeGcList; GcList mGcList; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp index 3037f64af747..ed9ba2281b96 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp @@ -29,7 +29,8 @@ namespace filament::backend { namespace { std::tuple createImageAndMemory(VulkanContext const& context, - VkDevice device, VkExtent2D extent, VkFormat format) { + VkDevice device, VkExtent2D extent, VkFormat format, + bool isProtected) { bool const isDepth = isVkDepthFormat(format); // Filament expects blit() to work with any texture, so we almost always set these usage flags // (see copyFrame() and readPixels()). @@ -38,6 +39,7 @@ std::tuple createImageAndMemory(VulkanContext const& co VkImageCreateInfo imageInfo { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = isProtected ? VK_IMAGE_CREATE_PROTECTED_BIT : VkImageCreateFlags(0), .imageType = VK_IMAGE_TYPE_2D, .format = format, .extent = {extent.width, extent.height, 1}, @@ -58,8 +60,11 @@ std::tuple createImageAndMemory(VulkanContext const& co VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device, image, &memReqs); + const VkFlags requiredMemoryFlags = + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + (isProtected ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0U); uint32_t memoryTypeIndex - = context.selectMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + = context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags); FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex < VK_MAX_MEMORY_TYPES) << "VulkanPlatformSwapChainImpl: unable to find a memory type that meets requirements."; @@ -110,8 +115,9 @@ void VulkanPlatformSwapChainImpl::destroy() { mSwapChainBundle.colors.clear(); } -VkImage VulkanPlatformSwapChainImpl::createImage(VkExtent2D extent, VkFormat format) { - auto [image, memory] = createImageAndMemory(mContext, mDevice, extent, format); +VkImage VulkanPlatformSwapChainImpl::createImage(VkExtent2D extent, VkFormat format, + bool isProtected) { + auto [image, memory] = createImageAndMemory(mContext, mDevice, extent, format, isProtected); mMemory.insert({image, memory}); return image; } @@ -248,7 +254,8 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { mSwapChainBundle.colorFormat = surfaceFormat.format; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil); - mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, mSwapChainBundle.depthFormat); + mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, + mSwapChainBundle.depthFormat, mIsProtected); mSwapChainBundle.isProtected = mIsProtected; FVK_LOGI << "vkCreateSwapchain" @@ -356,13 +363,13 @@ VulkanPlatformHeadlessSwapChain::VulkanPlatformHeadlessSwapChain(VulkanContext c images.reserve(HEADLESS_SWAPCHAIN_SIZE); images.resize(HEADLESS_SWAPCHAIN_SIZE); for (size_t i = 0; i < HEADLESS_SWAPCHAIN_SIZE; ++i) { - images[i] = createImage(extent, mSwapChainBundle.colorFormat); + images[i] = createImage(extent, mSwapChainBundle.colorFormat, false); } bool const hasStencil = (flags & backend::SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), hasStencil); - mSwapChainBundle.depth = createImage(extent, mSwapChainBundle.depthFormat); + mSwapChainBundle.depth = createImage(extent, mSwapChainBundle.depthFormat, false); } VulkanPlatformHeadlessSwapChain::~VulkanPlatformHeadlessSwapChain() { diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h index 2a715a210c27..ff1179d4ec3b 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.h @@ -73,7 +73,7 @@ struct VulkanPlatformSwapChainImpl : public Platform::SwapChain { // Non-virtual override-able method void destroy(); - VkImage createImage(VkExtent2D extent, VkFormat format); + VkImage createImage(VkExtent2D extent, VkFormat format, bool isProtected); VulkanContext const& mContext; VkDevice mDevice; diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 296fe6060210..eec97677948a 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -584,6 +584,10 @@ void FRenderer::render(FView const* view) { void FRenderer::renderInternal(FView const* view) { FEngine& engine = mEngine; + FILAMENT_CHECK_PRECONDITION(!view->hasPostProcessPass() || + engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1)) + << "post-processing is not supported at FEATURE_LEVEL_0"; + // per-renderpass data RootArenaScope rootArenaScope(engine.getPerRenderPassArena()); diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 44fe59269553..0d57d4405a5f 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.56.1" + spec.version = "1.56.2" 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.1/filament-v1.56.1-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.2/filament-v1.56.2-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/bluegl/CMakeLists.txt b/libs/bluegl/CMakeLists.txt index 9ce75c177dd1..704432cd15a8 100644 --- a/libs/bluegl/CMakeLists.txt +++ b/libs/bluegl/CMakeLists.txt @@ -36,6 +36,8 @@ elseif (APPLE AND NOT IOS) elseif(LINUX) if(FILAMENT_SUPPORTS_EGL_ON_LINUX) set(SRCS ${SRCS} src/BlueGLLinuxEGL.cpp) + elseif(FILAMENT_SUPPORTS_OSMESA) + set(SRCS ${SRCS} src/BlueGLLinuxOSMesa.cpp) else() set(SRCS ${SRCS} src/BlueGLLinux.cpp) endif() diff --git a/libs/bluegl/src/BlueGLLinuxOSMesa.cpp b/libs/bluegl/src/BlueGLLinuxOSMesa.cpp new file mode 100644 index 000000000000..182f5b2a5289 --- /dev/null +++ b/libs/bluegl/src/BlueGLLinuxOSMesa.cpp @@ -0,0 +1,59 @@ +/* + * 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 +#include + +namespace bluegl { + +namespace { +using ProcAddressFunc = void*(*)(char const* funcName); +} + +struct Driver { + ProcAddressFunc OSMesaGetProcAddress; + void* library; +} g_driver = {nullptr, nullptr}; + +bool initBinder() { + constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + for (char const* name : libraryNames) { + g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW); + if (g_driver.library) { + break; + } + } + if (!g_driver.library) { + return false; + } + + g_driver.OSMesaGetProcAddress = (ProcAddressFunc) + dlsym(g_driver.library, "OSMesaGetProcAddress"); + + return g_driver.OSMesaGetProcAddress; +} + +void* loadFunction(const char* name) { + return (void*) g_driver.OSMesaGetProcAddress(name); +} + +void shutdownBinder() { + dlclose(g_driver.library); + memset(&g_driver, 0, sizeof(g_driver)); +} + +} // namespace bluegl diff --git a/libs/utils/include/utils/Allocator.h b/libs/utils/include/utils/Allocator.h index 7b9978f5b902..254346048854 100644 --- a/libs/utils/include/utils/Allocator.h +++ b/libs/utils/include/utils/Allocator.h @@ -278,18 +278,23 @@ class AtomicFreeList { void* pop() noexcept { Node* const pStorage = mStorage; - HeadPtr currentHead = mHead.load(); + HeadPtr currentHead = mHead.load(std::memory_order_relaxed); while (currentHead.offset >= 0) { // The value of "pNext" we load here might already contain application data if another // thread raced ahead of us. But in that case, the computed "newHead" will be discarded - // since compare_exchange_weak fails. Then this thread will loop with the updated + // since compare_exchange_weak() fails. Then this thread will loop with the updated // value of currentHead, and try again. - Node* const pNext = pStorage[currentHead.offset].next.load(std::memory_order_relaxed); + // TSAN complains if we don't use a local variable here. + Node const node = pStorage[currentHead.offset]; + Node const* const pNext = node.next; const HeadPtr newHead{ pNext ? int32_t(pNext - pStorage) : -1, currentHead.tag + 1 }; - // In the rare case that the other thread that raced ahead of us already returned the - // same mHead we just loaded, but it now has a different "next" value, the tag field will not - // match, and compare_exchange_weak will fail and prevent that particular race condition. - if (mHead.compare_exchange_weak(currentHead, newHead)) { + // In the rare case that the other thread that raced ahead of us already returned the + // same mHead we just loaded, but it now has a different "next" value, the tag field + // will not match, and compare_exchange_weak() will fail and prevent that particular + // race condition. + // acquire: no read/write can be reordered before this + if (mHead.compare_exchange_weak(currentHead, newHead, + std::memory_order_acquire, std::memory_order_relaxed)) { // This assert needs to occur after we have validated that there was no race condition // Otherwise, next might already contain application data, if another thread // raced ahead of us after we loaded mHead, but before we loaded mHead->next. @@ -306,13 +311,15 @@ class AtomicFreeList { Node* const storage = mStorage; assert_invariant(p && p >= storage); Node* const node = static_cast(p); - HeadPtr currentHead = mHead.load(); + HeadPtr currentHead = mHead.load(std::memory_order_relaxed); HeadPtr newHead = { int32_t(node - storage), currentHead.tag + 1 }; do { newHead.tag = currentHead.tag + 1; - Node* const n = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr; - node->next.store(n, std::memory_order_relaxed); - } while(!mHead.compare_exchange_weak(currentHead, newHead)); + Node* const pNext = (currentHead.offset >= 0) ? (storage + currentHead.offset) : nullptr; + node->next = pNext; // could be a race with pop, corrected by CAS + } while(!mHead.compare_exchange_weak(currentHead, newHead, + std::memory_order_release, std::memory_order_relaxed)); + // release: no read/write can be reordered after this } void* getFirst() noexcept { @@ -320,10 +327,7 @@ class AtomicFreeList { } struct Node { - // This should be a regular (non-atomic) pointer, but this causes TSAN to complain - // about a data-race that exists but is benin. We always use this atomic<> in - // relaxed mode. - // The data race TSAN complains about is when a pop() is interrupted by a + // There is a benign data race when a pop() is interrupted by a // pop() + push() just after mHead->next is read -- it appears as though it is written // without synchronization (by the push), however in that case, the pop's CAS will fail // and things will auto-correct. @@ -346,7 +350,7 @@ class AtomicFreeList { // | // CAS, tag++ // - std::atomic next; + Node* next = nullptr; }; private: diff --git a/libs/utils/include/utils/JobSystem.h b/libs/utils/include/utils/JobSystem.h index 7ea711661a49..704755aa491a 100644 --- a/libs/utils/include/utils/JobSystem.h +++ b/libs/utils/include/utils/JobSystem.h @@ -446,7 +446,7 @@ class JobSystem { Condition mWaiterCondition; std::atomic mActiveJobs = { 0 }; - utils::Arena, LockingPolicy::NoLock> mJobPool; + utils::Arena, LockingPolicy::Mutex> mJobPool; template using aligned_vector = std::vector>; diff --git a/libs/utils/include/utils/ostream.h b/libs/utils/include/utils/ostream.h index cde8e75bd276..f55498517637 100644 --- a/libs/utils/include/utils/ostream.h +++ b/libs/utils/include/utils/ostream.h @@ -95,11 +95,11 @@ class UTILS_PUBLIC ostream : protected utils::PrivateImplementation { size_t length() const noexcept; private: - void reserve(size_t newSize) noexcept; + void reserve(size_t newCapacity) noexcept; char* buffer = nullptr; // buffer address char* curr = nullptr; // current pointer - size_t size = 0; // size remaining + size_t sizeRemaining = 0; // size remaining size_t capacity = 0; // total capacity of the buffer }; diff --git a/libs/utils/src/ostream.cpp b/libs/utils/src/ostream.cpp index 35ffab843475..c50d0c293b87 100644 --- a/libs/utils/src/ostream.cpp +++ b/libs/utils/src/ostream.cpp @@ -237,23 +237,23 @@ ostream::Buffer::~Buffer() noexcept { void ostream::Buffer::advance(ssize_t n) noexcept { if (n > 0) { - size_t const written = n < size ? size_t(n) : size; + size_t const written = n < sizeRemaining ? size_t(n) : sizeRemaining; curr += written; - size -= written; + sizeRemaining -= written; } } -void ostream::Buffer::reserve(size_t newSize) noexcept { +void ostream::Buffer::reserve(size_t newCapacity) noexcept { size_t const offset = curr - buffer; if (buffer == nullptr) { - buffer = (char*)malloc(newSize); + buffer = (char*)malloc(newCapacity); } else { - buffer = (char*)realloc(buffer, newSize); + buffer = (char*)realloc(buffer, newCapacity); } assert(buffer); - capacity = newSize; + capacity = newCapacity; curr = buffer + offset; - size = capacity - offset; + sizeRemaining = capacity - offset; } void ostream::Buffer::reset() noexcept { @@ -264,7 +264,7 @@ void ostream::Buffer::reset() noexcept { capacity = 1024; } curr = buffer; - size = capacity; + sizeRemaining = capacity; } size_t ostream::Buffer::length() const noexcept { @@ -272,13 +272,14 @@ size_t ostream::Buffer::length() const noexcept { } std::pair ostream::Buffer::grow(size_t s) noexcept { - if (UTILS_UNLIKELY(size < s)) { - size_t const used = curr - buffer; - size_t const newCapacity = std::max(size_t(32), used + (s * 3 + 1) / 2); // 32 bytes minimum + if (UTILS_UNLIKELY(sizeRemaining < s)) { + size_t const usedSize = curr - buffer; + size_t const neededCapacity = usedSize + s; + size_t const newCapacity = std::max(size_t(32), (neededCapacity * 3 + 1) / 2); // 32 bytes minimum reserve(newCapacity); - assert(size >= s); + assert(sizeRemaining >= s); } - return { curr, size }; + return { curr, sizeRemaining }; } } // namespace utils::io diff --git a/shaders/src/shadowing.fs b/shaders/src/shadowing.fs index 50f44e26c1d6..061aec25a3bd 100644 --- a/shaders/src/shadowing.fs +++ b/shaders/src/shadowing.fs @@ -19,7 +19,7 @@ float sampleDepth(const mediump sampler2DArrayShadow map, const highp vec4 scissorNormalized, - const uint layer, highp vec2 uv, float depth) { + const uint layer, highp vec2 uv, highp float depth) { // clamp needed for directional lights and/or large kernels uv = clamp(uv, scissorNormalized.xy, scissorNormalized.zw); @@ -51,7 +51,7 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map, highp vec2 texelSize = vec2(1.0) / size; // CastaƱo, 2013, "Shadow Mapping Summary Part 1" - float depth = position.z; + highp float depth = position.z; // clamp position to avoid overflows below, which cause some GPUs to abort position.xy = clamp(position.xy, vec2(-1.0), vec2(2.0)); diff --git a/web/filament-js/package.json b/web/filament-js/package.json index bbca1748ed75..8022284f92ca 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.56.1", + "version": "1.56.2", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",