From bcf5e78cbf315703e85d15e95dd2bfddc7787c52 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 8 Jan 2026 12:26:47 +0000 Subject: [PATCH 01/15] Moved DynamicData into ResourceHints. --- CMakeLists.txt | 4 +- include/vsg/app/CompileManager.h | 2 +- include/vsg/app/TransferTask.h | 2 +- include/vsg/state/ResourceHints.h | 32 +++++++++++++ include/vsg/vk/ResourceRequirements.h | 28 +++-------- src/vsg/app/TransferTask.cpp | 2 +- src/vsg/state/ResourceHints.cpp | 26 +++++++++++ src/vsg/vk/ResourceRequirements.cpp | 67 ++++++++++++++++++++------- 8 files changed, 119 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c3d5522b2..fec2e101f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.10) project(vsg - VERSION 1.1.13 + VERSION 1.1.14 DESCRIPTION "VulkanSceneGraph library" LANGUAGES CXX ) -set(VSG_SOVERSION 15) +set(VSG_SOVERSION 16) SET(VSG_RELEASE_CANDIDATE 0) set(Vulkan_MIN_VERSION 1.1.70.0) diff --git a/include/vsg/app/CompileManager.h b/include/vsg/app/CompileManager.h index 342ee14d76..dff3c9f905 100644 --- a/include/vsg/app/CompileManager.h +++ b/include/vsg/app/CompileManager.h @@ -30,7 +30,7 @@ namespace vsg Slots maxSlots; bool containsPagedLOD = false; ResourceRequirements::Views views; - ResourceRequirements::DynamicData dynamicData; + DynamicData dynamicData; explicit operator bool() const noexcept { return result == VK_SUCCESS; } diff --git a/include/vsg/app/TransferTask.h b/include/vsg/app/TransferTask.h index b098bbb0b6..54a60f825c 100644 --- a/include/vsg/app/TransferTask.h +++ b/include/vsg/app/TransferTask.h @@ -51,7 +51,7 @@ namespace vsg ref_ptr device; - void assign(const ResourceRequirements::DynamicData& dynamicData); + void assign(const DynamicData& dynamicData); void assign(const BufferInfoList& bufferInfoList); void assign(const ImageInfoList& imageInfoList); diff --git a/include/vsg/state/ResourceHints.h b/include/vsg/state/ResourceHints.h index 3c1fc019f1..614fb4ab71 100644 --- a/include/vsg/state/ResourceHints.h +++ b/include/vsg/state/ResourceHints.h @@ -14,6 +14,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include +#include namespace vsg { @@ -30,6 +32,26 @@ namespace vsg DYNAMIC_VIEWPORTSTATE = 1 << 1 }; + struct DynamicData + { + BufferInfoList bufferInfos; + ImageInfoList imageInfos; + + explicit operator bool() const noexcept { return !bufferInfos.empty() || !imageInfos.empty(); } + + void clear() + { + bufferInfos.clear(); + imageInfos.clear(); + } + + void add(const DynamicData& dd) + { + bufferInfos.insert(bufferInfos.end(), dd.bufferInfos.begin(), dd.bufferInfos.end()); + imageInfos.insert(imageInfos.end(), dd.imageInfos.begin(), dd.imageInfos.end()); + } + }; + /// ResourceHints provides settings that help preallocation of Vulkan resources and memory. class VSG_DECLSPEC ResourceHints : public Inherit { @@ -56,6 +78,16 @@ namespace vsg DataTransferHint dataTransferHint = COMPILE_TRAVERSAL_USE_TRANSFER_TASK; uint32_t viewportStateHint = DYNAMIC_VIEWPORTSTATE; + VkDeviceSize bufferMemoryRequirements = 0; + VkDeviceSize imageMemoryRequirements = 0; + + DynamicData dynamicData; + + bool containsPagedLOD = false; + + /// hint whether CollectResourceRequirements visitor should traverse the subgraph below a node that has a "ResourceHints" assignd as meta data. + bool noTraverseBelowResourceHints = false; + public: void read(Input& input) override; void write(Output& output) const override; diff --git a/include/vsg/vk/ResourceRequirements.h b/include/vsg/vk/ResourceRequirements.h index 332779f3a9..33d0c34e17 100644 --- a/include/vsg/vk/ResourceRequirements.h +++ b/include/vsg/vk/ResourceRequirements.h @@ -60,26 +60,6 @@ namespace vsg using Views = std::map; using ViewDetailStack = std::stack; - struct DynamicData - { - BufferInfoList bufferInfos; - ImageInfoList imageInfos; - - explicit operator bool() const noexcept { return !bufferInfos.empty() || !imageInfos.empty(); } - - void clear() - { - bufferInfos.clear(); - imageInfos.clear(); - } - - void add(const DynamicData& dd) - { - bufferInfos.insert(bufferInfos.end(), dd.bufferInfos.begin(), dd.bufferInfos.end()); - imageInfos.insert(imageInfos.end(), dd.imageInfos.begin(), dd.imageInfos.end()); - } - }; - DynamicData dynamicData; Descriptors descriptors; @@ -92,6 +72,12 @@ namespace vsg uint32_t externalNumDescriptorSets = 0; bool containsPagedLOD = false; + std::set> bufferInfos; + std::set> imageInfos; + + VkDeviceSize bufferMemoryRequirements = 0; + VkDeviceSize imageMemoryRequirements = 0; + VkDeviceSize minimumBufferSize = 16 * 1024 * 1024; VkDeviceSize minimumDeviceMemorySize = 16 * 1024 * 1024; @@ -146,8 +132,6 @@ namespace vsg virtual void apply(ref_ptr imageInfo); protected: - uint32_t _numResourceHintsAbove = 0; - bool registerDescriptor(const Descriptor& descriptor); }; VSG_type_name(vsg::CollectResourceRequirements); diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index cf320b2a59..1aa2a6e3e4 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -51,7 +51,7 @@ void TransferTask::assignTransferConsumedCompletedSemaphore(TransferMask transfe if ((transferMask & TRANSFER_AFTER_RECORD_TRAVERSAL) != 0) _lateDataToCopy.transferConsumerCompletedSemaphore = semaphore; } -void TransferTask::assign(const ResourceRequirements::DynamicData& dynamicData) +void TransferTask::assign(const DynamicData& dynamicData) { CPU_INSTRUMENTATION_L2(instrumentation); diff --git a/src/vsg/state/ResourceHints.cpp b/src/vsg/state/ResourceHints.cpp index 9b45dddf01..ff9052c635 100644 --- a/src/vsg/state/ResourceHints.cpp +++ b/src/vsg/state/ResourceHints.cpp @@ -74,6 +74,19 @@ void ResourceHints::read(Input& input) { input.read("viewportStateHint", viewportStateHint); } + + if (input.version_greater_equal(1, 1, 14)) + { + input.read("bufferMemoryRequirements", bufferMemoryRequirements); + input.read("imageMemoryRequirements", imageMemoryRequirements); + + input.readObjects("dynamicData.bufferInfos", dynamicData.bufferInfos); + input.readObjects("dynamicData.imageInfos", dynamicData.imageInfos); + + input.read("containsPagedLOD", containsPagedLOD); + + input.read("noTraverseBelowResourceHints", noTraverseBelowResourceHints); + } } void ResourceHints::write(Output& output) const @@ -127,4 +140,17 @@ void ResourceHints::write(Output& output) const { output.write("viewportStateHint", viewportStateHint); } + + if (output.version_greater_equal(1, 1, 14)) + { + output.write("bufferMemoryRequirements", bufferMemoryRequirements); + output.write("imageMemoryRequirements", imageMemoryRequirements); + + output.writeObjects("dynamicData.bufferInfos", dynamicData.bufferInfos); + output.writeObjects("dynamicData.imageInfos", dynamicData.imageInfos); + + output.write("containsPagedLOD", containsPagedLOD); + + output.write("noTraverseBelowResourceHints", noTraverseBelowResourceHints); + } } diff --git a/src/vsg/vk/ResourceRequirements.cpp b/src/vsg/vk/ResourceRequirements.cpp index e5e585b1e8..d7cd9842c3 100644 --- a/src/vsg/vk/ResourceRequirements.cpp +++ b/src/vsg/vk/ResourceRequirements.cpp @@ -85,6 +85,11 @@ void ResourceRequirements::apply(const ResourceHints& resourceHints) dataTransferHint = resourceHints.dataTransferHint; viewportStateHint = resourceHints.viewportStateHint; + + bufferMemoryRequirements += resourceHints.bufferMemoryRequirements; + imageMemoryRequirements += resourceHints.imageMemoryRequirements; + dynamicData.add(resourceHints.dynamicData); + containsPagedLOD = containsPagedLOD | resourceHints.containsPagedLOD; } ////////////////////////////////////////////////////////////////////// @@ -104,6 +109,13 @@ ref_ptr CollectResourceRequirements::createResourceHints(uint32_t poolSize.descriptorCount = poolSize.descriptorCount * tileMultiplier; } + resourceHints->bufferMemoryRequirements = requirements.bufferMemoryRequirements; + resourceHints->imageMemoryRequirements = requirements.imageMemoryRequirements; + resourceHints->dynamicData = requirements.dynamicData; + resourceHints->containsPagedLOD = requirements.containsPagedLOD; + + resourceHints->noTraverseBelowResourceHints = true; + return resourceHints; } @@ -118,7 +130,7 @@ bool CollectResourceRequirements::checkForResourceHints(const Object& object) if (resourceHints) { apply(*resourceHints); - return true; + return resourceHints->noTraverseBelowResourceHints; } else { @@ -133,23 +145,24 @@ void CollectResourceRequirements::apply(const ResourceHints& resourceHints) void CollectResourceRequirements::apply(const Node& node) { - bool hasResourceHints = checkForResourceHints(node); - if (hasResourceHints) ++_numResourceHintsAbove; + if (checkForResourceHints(node)) + { + return; + } node.traverse(*this); - - if (hasResourceHints) --_numResourceHintsAbove; } void CollectResourceRequirements::apply(const PagedLOD& plod) { - bool hasResourceHints = checkForResourceHints(plod); - if (hasResourceHints) ++_numResourceHintsAbove; - requirements.containsPagedLOD = true; - plod.traverse(*this); - if (hasResourceHints) --_numResourceHintsAbove; + if (checkForResourceHints(plod)) + { + return; + } + + plod.traverse(*this); } void CollectResourceRequirements::apply(const StateCommand& stateCommand) @@ -302,21 +315,41 @@ void CollectResourceRequirements::apply(const BindIndexBuffer& bib) void CollectResourceRequirements::apply(ref_ptr bufferInfo) { - if (bufferInfo && bufferInfo->data && bufferInfo->data->dynamic()) + if (bufferInfo && requirements.bufferInfos.count(bufferInfo)==0) { - requirements.dynamicData.bufferInfos.push_back(bufferInfo); + requirements.bufferInfos.insert(bufferInfo); + + if (bufferInfo->data) + { + if (bufferInfo->data->dynamic()) + { + requirements.dynamicData.bufferInfos.push_back(bufferInfo); + } + + requirements.bufferMemoryRequirements += bufferInfo->data->dataSize(); + } } } void CollectResourceRequirements::apply(ref_ptr imageInfo) { - if (imageInfo && imageInfo->imageView && imageInfo->imageView->image) + if (imageInfo && requirements.imageInfos.count(imageInfo)==0) { - // check for dynamic data - auto& data = imageInfo->imageView->image->data; - if (data && data->dynamic()) + if (imageInfo->imageView && imageInfo->imageView->image) { - requirements.dynamicData.imageInfos.push_back(imageInfo); + requirements.imageInfos.insert(imageInfo); + + // check for dynamic data + auto& data = imageInfo->imageView->image->data; + if (data) + { + if (data->dynamic()) + { + requirements.dynamicData.imageInfos.push_back(imageInfo); + } + + requirements.imageMemoryRequirements += data->dataSize(); + } } } } From 0915da248c8831d3081f3f0c469f3ebed708f01d Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 8 Jan 2026 13:41:05 +0000 Subject: [PATCH 02/15] Added ability to query available memory --- include/vsg/app/CompileManager.h | 6 +++++ include/vsg/vk/Device.h | 3 +++ src/vsg/app/CompileManager.cpp | 44 +++++++++++++++++++++++++++++--- src/vsg/vk/Device.cpp | 22 ++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/include/vsg/app/CompileManager.h b/include/vsg/app/CompileManager.h index dff3c9f905..53dcba5718 100644 --- a/include/vsg/app/CompileManager.h +++ b/include/vsg/app/CompileManager.h @@ -65,6 +65,9 @@ namespace vsg using ContextSelectionFunction = std::function; + /// return the smallest available memory on the associated devices + VkDeviceSize availableMemory(ContextSelectionFunction contextSelection = {}) const; + /// compile object CompileResult compile(ref_ptr object, ContextSelectionFunction contextSelection = {}); @@ -72,6 +75,9 @@ namespace vsg CompileResult compileTask(ref_ptr task, const ResourceRequirements& resourceRequirements = {}); protected: + + std::list> contexts; + using CompileTraversals = ThreadSafeQueue>; size_t numCompileTraversals = 0; ref_ptr compileTraversals; diff --git a/include/vsg/vk/Device.h b/include/vsg/vk/Device.h index a36f4bb45f..bd3f8c2b47 100644 --- a/include/vsg/vk/Device.h +++ b/include/vsg/vk/Device.h @@ -84,6 +84,9 @@ namespace vsg /// return true if Device was created with specified extension bool supportsDeviceExtension(const char* extensionName) const; + /// return the amount of memory available in deviceMemoryBufferPools and allocatable on device + VkDeviceSize availableMemory() const; + // provide observer_ptr to memory buffer and descriptor pools so that these can be accessed when required observer_ptr deviceMemoryBufferPools; observer_ptr stagingMemoryBufferPools; diff --git a/src/vsg/app/CompileManager.cpp b/src/vsg/app/CompileManager.cpp index 75d8c24ce0..8928c75c19 100644 --- a/src/vsg/app/CompileManager.cpp +++ b/src/vsg/app/CompileManager.cpp @@ -82,6 +82,8 @@ CompileManager::CompileManager(Viewer& viewer, ref_ptr hints) #else numCompileTraversals = 1; #endif + + contexts = ct->contexts; } CompileManager::CompileTraversals::container_type CompileManager::takeCompileTraversals(size_t count) @@ -106,6 +108,8 @@ void CompileManager::add(ref_ptr device, const ResourceRequirements& res { ct->add(device, resourceRequirements); + contexts = ct->contexts; + compileTraversals->add(ct); } } @@ -117,6 +121,8 @@ void CompileManager::add(Window& window, ref_ptr viewport, const { ct->add(window, viewport, resourceRequirements); + contexts = ct->contexts; + compileTraversals->add(ct); } } @@ -128,6 +134,8 @@ void CompileManager::add(Window& window, ref_ptr view, const ResourceRequi { ct->add(window, view, resourceRequirements); + contexts = ct->contexts; + compileTraversals->add(ct); } } @@ -139,6 +147,8 @@ void CompileManager::add(Framebuffer& framebuffer, ref_ptr view, const Res { ct->add(framebuffer, view, resourceRequirements); + contexts = ct->contexts; + compileTraversals->add(ct); } } @@ -150,6 +160,8 @@ void CompileManager::add(const Viewer& viewer, const ResourceRequirements& resou { ct->add(viewer, resourceRequirements); + contexts = ct->contexts; + compileTraversals->add(ct); } } @@ -165,6 +177,30 @@ void CompileManager::assignInstrumentation(ref_ptr in_instrumen } } +VkDeviceSize CompileManager::availableMemory(ContextSelectionFunction contextSelection) const +{ + VkDeviceSize minAvailable = std::numeric_limits::max(); + + if (contextSelection) + { + for (auto& context : contexts) + { + if (contextSelection(*context)) minAvailable = std::min(minAvailable, context->device->availableMemory()); + } + } + else + { + for (auto& context : contexts) + { + minAvailable = std::min(minAvailable, context->device->availableMemory()); + } + } + + vsg::info("CompileManager::availableMemory() = ", minAvailable); + + return minAvailable; +} + CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFunction contextSelection) { vsg::debug("CompileManager::compile(", object, ", ..)"); @@ -241,18 +277,18 @@ CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFu if (contextSelection) { - std::list> contexts; + std::list> activeContexts; for (auto& context : compileTraversal->contexts) { - if (contextSelection(*context)) contexts.push_back(context); + if (contextSelection(*context)) activeContexts.push_back(context); } - compileTraversal->contexts.swap(contexts); + compileTraversal->contexts.swap(activeContexts); run_compile_traversal(); - compileTraversal->contexts.swap(contexts); + compileTraversal->contexts.swap(activeContexts); } else { diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index c0f86f35df..653d7f9c6c 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -205,3 +205,25 @@ bool Device::supportsDeviceExtension(const char* extensionName) const auto compare = [&](const char* rhs) { return strcmp(extensionName, rhs) == 0; }; return (std::find_if(enabledExtensions.begin(), enabledExtensions.end(), compare) != enabledExtensions.end()); } + +VkDeviceSize Device::availableMemory() const +{ + VkDeviceSize available = 0; +#if 0 + VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; + memoryBudget.pNext = nullptr; + + VkPhysicalDeviceMemoryProperties2 memoryProperties; + memoryProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + memoryProperties.pNext = &memoryBudget; + + vkGetPhysicalDeviceMemoryProperties2(*(device->getPhysicalDevice()), &memoryProperties); +#endif + if (auto pool = deviceMemoryBufferPools.ref_ptr()) + { + available += pool->computeMemoryTotalAvailable(); + } + + return available; +} From cd15add2448cc3e9245c265314e4a1113bab1e93 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 14 Jan 2026 11:45:04 +0000 Subject: [PATCH 03/15] Added support for compile failure. --- src/vsg/io/DatabasePager.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vsg/io/DatabasePager.cpp b/src/vsg/io/DatabasePager.cpp index ca96f187b6..40d49e2c2e 100644 --- a/src/vsg/io/DatabasePager.cpp +++ b/src/vsg/io/DatabasePager.cpp @@ -515,17 +515,23 @@ void DatabasePager::start(uint32_t numReadThreads) plod->pending = subgraph; } - // compile plod - if (auto result = databasePager.compileManager->compile(subgraph)) + try { - plod->requestStatus.exchange(PagedLOD::MergeRequest); + // compile plod + if (auto result = databasePager.compileManager->compile(subgraph)) + { + plod->requestStatus.exchange(PagedLOD::MergeRequest); - // move to the merge queue; - databasePager._toMergeQueue->add(plod, result); + // move to the merge queue; + databasePager._toMergeQueue->add(plod, result); + } + else + { + databasePager.requestDiscarded(plod); + } } - else + catch(...) { - debug("Failed to compile ", plod, " ", plod->filename); databasePager.requestDiscarded(plod); } } From 7ebf96891a1b1db0d683a5d1ffd37c45bf4c8563 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 23 Jan 2026 19:10:51 +0000 Subject: [PATCH 04/15] Refined the handling of allocation of new memory and buffers to ensure that newly compiled paged databases don't exceed memory limits and cause a crash. --- include/vsg/app/CompileManager.h | 5 - include/vsg/state/Image.h | 5 +- include/vsg/vk/Context.h | 2 +- include/vsg/vk/Device.h | 2 +- include/vsg/vk/MemoryBufferPools.h | 5 + include/vsg/vk/ResourceRequirements.h | 17 ++- src/vsg/app/CompileManager.cpp | 54 +------ src/vsg/io/DatabasePager.cpp | 2 + src/vsg/state/BufferInfo.cpp | 13 +- src/vsg/state/Image.cpp | 52 +++++-- src/vsg/state/ImageView.cpp | 2 +- src/vsg/vk/Context.cpp | 6 +- src/vsg/vk/Device.cpp | 45 ++++-- src/vsg/vk/MemoryBufferPools.cpp | 199 ++++++++++++++++++++++---- src/vsg/vk/ResourceRequirements.cpp | 114 ++++++++++++--- 15 files changed, 391 insertions(+), 132 deletions(-) diff --git a/include/vsg/app/CompileManager.h b/include/vsg/app/CompileManager.h index 53dcba5718..c437a71c2d 100644 --- a/include/vsg/app/CompileManager.h +++ b/include/vsg/app/CompileManager.h @@ -65,9 +65,6 @@ namespace vsg using ContextSelectionFunction = std::function; - /// return the smallest available memory on the associated devices - VkDeviceSize availableMemory(ContextSelectionFunction contextSelection = {}) const; - /// compile object CompileResult compile(ref_ptr object, ContextSelectionFunction contextSelection = {}); @@ -76,8 +73,6 @@ namespace vsg protected: - std::list> contexts; - using CompileTraversals = ThreadSafeQueue>; size_t numCompileTraversals = 0; ref_ptr compileTraversals; diff --git a/include/vsg/state/Image.h b/include/vsg/state/Image.h index 7be6a50c37..9a802e1a7d 100644 --- a/include/vsg/state/Image.h +++ b/include/vsg/state/Image.h @@ -67,8 +67,9 @@ namespace vsg /// return true if the Image's data has been modified and should be copied to the buffer, updating the device specific ModifiedCount to the Data's ModifiedCount. bool syncModifiedCount(uint32_t deviceID) { return data && data->getModifiedCount(_vulkanData[deviceID].copiedModifiedCount); } - virtual void compile(Device* device); - virtual void compile(Context& context); + virtual VkResult compile(Device* device); + virtual VkResult compile(Context& context); + virtual VkResult compile(MemoryBufferPools& memoryBufferPools); protected: virtual ~Image(); diff --git a/include/vsg/vk/Context.h b/include/vsg/vk/Context.h index 890f17be0e..daa5bb1ede 100644 --- a/include/vsg/vk/Context.h +++ b/include/vsg/vk/Context.h @@ -87,7 +87,7 @@ namespace vsg ref_ptr getOrCreateCommandBuffer(); /// reserve resources that may be needed during compile traversal. - void reserve(const ResourceRequirements& requirements); + VkResult reserve(ResourceRequirements& requirements); ref_ptr allocateDescriptorSet(DescriptorSetLayout* descriptorSetLayout); diff --git a/include/vsg/vk/Device.h b/include/vsg/vk/Device.h index bd3f8c2b47..5e514ddfc9 100644 --- a/include/vsg/vk/Device.h +++ b/include/vsg/vk/Device.h @@ -85,7 +85,7 @@ namespace vsg bool supportsDeviceExtension(const char* extensionName) const; /// return the amount of memory available in deviceMemoryBufferPools and allocatable on device - VkDeviceSize availableMemory() const; + VkDeviceSize availableMemory(bool includeMemoryPools = true) const; // provide observer_ptr to memory buffer and descriptor pools so that these can be accessed when required observer_ptr deviceMemoryBufferPools; diff --git a/include/vsg/vk/MemoryBufferPools.h b/include/vsg/vk/MemoryBufferPools.h index 7f59118691..ca2e413346 100644 --- a/include/vsg/vk/MemoryBufferPools.h +++ b/include/vsg/vk/MemoryBufferPools.h @@ -44,6 +44,11 @@ namespace vsg using DeviceMemoryOffset = std::pair, VkDeviceSize>; DeviceMemoryOffset reserveMemory(VkMemoryRequirements memRequirements, VkMemoryPropertyFlags memoryProperties, void* pNextAllocInfo = nullptr); + VkResult reserve(ResourceRequirements& requirements); + + VkDeviceSize computeSize(BufferInfo& bufferInfo) const; + VkDeviceSize computeSize(ImageInfo& imageInfo) const; + protected: mutable std::mutex _mutex; diff --git a/include/vsg/vk/ResourceRequirements.h b/include/vsg/vk/ResourceRequirements.h index 33d0c34e17..66bc596f2e 100644 --- a/include/vsg/vk/ResourceRequirements.h +++ b/include/vsg/vk/ResourceRequirements.h @@ -72,7 +72,15 @@ namespace vsg uint32_t externalNumDescriptorSets = 0; bool containsPagedLOD = false; - std::set> bufferInfos; + struct BufferProperties + { + VkBufferUsageFlags usageFlags = 0; + VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + bool operator < (const BufferProperties& rhs) const { return (usageFlags < rhs.usageFlags) || ((usageFlags == rhs.usageFlags) && (sharingMode < rhs.sharingMode)); } + }; + + std::map>> bufferInfos; std::set> imageInfos; VkDeviceSize bufferMemoryRequirements = 0; @@ -127,8 +135,13 @@ namespace vsg void apply(const VertexIndexDraw& vid) override; void apply(const BindVertexBuffers& bvb) override; void apply(const BindIndexBuffer& bib) override; + void apply(const InstanceNode& in) override; + void apply(const InstanceDraw& id) override; + void apply(const InstanceDrawIndexed& idi) override; + + using BufferProperties = ResourceRequirements::BufferProperties; - virtual void apply(ref_ptr bufferInfo); + virtual void apply(ref_ptr bufferInfo, BufferProperties bufferProperties); virtual void apply(ref_ptr imageInfo); protected: diff --git a/src/vsg/app/CompileManager.cpp b/src/vsg/app/CompileManager.cpp index 8928c75c19..6c7f05db60 100644 --- a/src/vsg/app/CompileManager.cpp +++ b/src/vsg/app/CompileManager.cpp @@ -82,8 +82,6 @@ CompileManager::CompileManager(Viewer& viewer, ref_ptr hints) #else numCompileTraversals = 1; #endif - - contexts = ct->contexts; } CompileManager::CompileTraversals::container_type CompileManager::takeCompileTraversals(size_t count) @@ -107,9 +105,6 @@ void CompileManager::add(ref_ptr device, const ResourceRequirements& res for (auto& ct : cts) { ct->add(device, resourceRequirements); - - contexts = ct->contexts; - compileTraversals->add(ct); } } @@ -120,9 +115,6 @@ void CompileManager::add(Window& window, ref_ptr viewport, const for (auto& ct : cts) { ct->add(window, viewport, resourceRequirements); - - contexts = ct->contexts; - compileTraversals->add(ct); } } @@ -133,9 +125,6 @@ void CompileManager::add(Window& window, ref_ptr view, const ResourceRequi for (auto& ct : cts) { ct->add(window, view, resourceRequirements); - - contexts = ct->contexts; - compileTraversals->add(ct); } } @@ -146,9 +135,6 @@ void CompileManager::add(Framebuffer& framebuffer, ref_ptr view, const Res for (auto& ct : cts) { ct->add(framebuffer, view, resourceRequirements); - - contexts = ct->contexts; - compileTraversals->add(ct); } } @@ -159,9 +145,6 @@ void CompileManager::add(const Viewer& viewer, const ResourceRequirements& resou for (auto& ct : cts) { ct->add(viewer, resourceRequirements); - - contexts = ct->contexts; - compileTraversals->add(ct); } } @@ -172,39 +155,12 @@ void CompileManager::assignInstrumentation(ref_ptr in_instrumen for (auto& ct : cts) { ct->assignInstrumentation(in_instrumentation); - compileTraversals->add(ct); } } -VkDeviceSize CompileManager::availableMemory(ContextSelectionFunction contextSelection) const -{ - VkDeviceSize minAvailable = std::numeric_limits::max(); - - if (contextSelection) - { - for (auto& context : contexts) - { - if (contextSelection(*context)) minAvailable = std::min(minAvailable, context->device->availableMemory()); - } - } - else - { - for (auto& context : contexts) - { - minAvailable = std::min(minAvailable, context->device->availableMemory()); - } - } - - vsg::info("CompileManager::availableMemory() = ", minAvailable); - - return minAvailable; -} - CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFunction contextSelection) { - vsg::debug("CompileManager::compile(", object, ", ..)"); - CollectResourceRequirements collectRequirements; object->accept(collectRequirements); @@ -243,13 +199,13 @@ CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFu } } } - context->reserve(requirements); + + auto reserveResult = context->reserve(requirements); + if (reserveResult != VK_SUCCESS) throw vsg::Exception{"Context::reserve() failed", reserveResult}; } object->accept(*compileTraversal); - //debug("Finished compile traversal ", object); - // if required records and submits to queue if (compileTraversal->record()) { @@ -258,13 +214,11 @@ CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFu } catch (const vsg::Exception& ve) { - vsg::debug("CompileManager::compile() exception caught : ", ve.message); result.message = ve.message; result.result = ve.result; } catch (...) { - vsg::debug("CompileManager::compile() exception caught"); result.message = "Exception occurred during compilation."; result.result = VK_ERROR_UNKNOWN; } @@ -272,7 +226,7 @@ CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFu debug("Finished waiting for compile ", object); }; - // assume success, overite this on failures. + // assume success, overwrite this on failures. result.result = VK_SUCCESS; if (contextSelection) diff --git a/src/vsg/io/DatabasePager.cpp b/src/vsg/io/DatabasePager.cpp index 40d49e2c2e..1627be9531 100644 --- a/src/vsg/io/DatabasePager.cpp +++ b/src/vsg/io/DatabasePager.cpp @@ -527,11 +527,13 @@ void DatabasePager::start(uint32_t numReadThreads) } else { + debug("DatabaserPager::start() unable to compile subgraph, discarding request ", subgraph); databasePager.requestDiscarded(plod); } } catch(...) { + debug("DatabaserPager::start() compile threw exception, discarding request ", subgraph); databasePager.requestDiscarded(plod); } } diff --git a/src/vsg/state/BufferInfo.cpp b/src/vsg/state/BufferInfo.cpp index 3e3c41821d..c4961cb055 100644 --- a/src/vsg/state/BufferInfo.cpp +++ b/src/vsg/state/BufferInfo.cpp @@ -256,7 +256,12 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu vkGetBufferMemoryRequirements(*device, deviceBufferInfo->buffer->vk(device->deviceID), &memRequirements); auto deviceMemoryOffset = context.deviceMemoryBufferPools->reserveMemory(memRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - deviceBufferInfo->buffer->bind(deviceMemoryOffset.first, deviceMemoryOffset.second); + if (!deviceMemoryOffset.first) deviceBufferInfo->buffer->bind(deviceMemoryOffset.first, deviceMemoryOffset.second); + else + { + info("vsg::createBufferAndTransferData() Failure to assign memory to existing BufferInfo"); + return false; + } } } } @@ -267,6 +272,12 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu deviceBufferInfo = context.deviceMemoryBufferPools->reserveBuffer(totalSize, alignment, bufferUsageFlags, sharingMode, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } + if (!deviceBufferInfo) + { + info("vsg::createBufferAndTransferData() Failure to assign Buffer"); + return false; + } + debug("deviceBufferInfo->buffer ", deviceBufferInfo->buffer, ", ", deviceBufferInfo->offset, ", ", deviceBufferInfo->range, ")"); // assign the buffer to the bufferData entries and shift the offsets to offset within the buffer diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index c63813fb8b..90ef0db414 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -188,10 +188,10 @@ VkMemoryRequirements Image::getMemoryRequirements(uint32_t deviceID) const return memRequirements; } -void Image::compile(Device* device) +VkResult Image::compile(Device* device) { auto& vd = _vulkanData[device->deviceID]; - if (vd.image != VK_NULL_HANDLE) return; + if (vd.image != VK_NULL_HANDLE) return VK_SUCCESS; VkImageCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -216,30 +216,52 @@ void Image::compile(Device* device) vd.requiresDataCopy = data.valid(); - if (VkResult result = vkCreateImage(*vd.device, &info, vd.device->getAllocationCallbacks(), &vd.image); result != VK_SUCCESS) + VkResult result = vkCreateImage(*vd.device, &info, vd.device->getAllocationCallbacks(), &vd.image); + + if (result != VK_SUCCESS) { throw Exception{"Error: Failed to create VkImage.", result}; } + + return result; } -void Image::compile(Context& context) +VkResult Image::compile(Context& context) { - auto& vd = _vulkanData[context.deviceID]; - if (vd.image != VK_NULL_HANDLE) return; + try + { + return compile(*context.deviceMemoryBufferPools); + } + catch(...) + { + vsg::info("Image::compile(Context& context)"); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } +} - compile(context.device); +VkResult Image::compile(MemoryBufferPools& memoryBufferPools) +{ + auto device = memoryBufferPools.device; + auto& vd = _vulkanData[device->deviceID]; + if (vd.image != VK_NULL_HANDLE) return VK_SUCCESS; - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(*vd.device, vd.image, &memRequirements); + VkResult result = compile(device); + if (result != VK_SUCCESS) return result; - auto [deviceMemory, offset] = context.deviceMemoryBufferPools->reserveMemory(memRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(*device, vd.image, &memRequirements); - if (!deviceMemory) + auto [deviceMemory, offset] = memoryBufferPools.reserveMemory(memRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (deviceMemory) { - throw Exception{"Error: Image failed to reserve slot from deviceMemoryBufferPools.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; + vd.requiresDataCopy = data.valid(); + bind(deviceMemory, offset); + } + else + { + // throw Exception{"Error: Image failed to reserve slot from deviceMemoryBufferPools.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; } - vd.requiresDataCopy = data.valid(); - - bind(deviceMemory, offset); + return result; } diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index e8d8a722ea..de103cb00a 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -14,7 +14,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include - +#include using namespace vsg; VkImageAspectFlags vsg::computeAspectFlagsForFormat(VkFormat format) diff --git a/src/vsg/vk/Context.cpp b/src/vsg/vk/Context.cpp index fb2fa0215d..cfee9f707c 100644 --- a/src/vsg/vk/Context.cpp +++ b/src/vsg/vk/Context.cpp @@ -193,13 +193,17 @@ ShaderCompiler* Context::getOrCreateShaderCompiler() return shaderCompiler; } -void Context::reserve(const ResourceRequirements& requirements) +VkResult Context::reserve(ResourceRequirements& requirements) { CPU_INSTRUMENTATION_L2_NC(instrumentation, "Context reserve", COLOR_COMPILE) + VkResult result = deviceMemoryBufferPools->reserve(requirements); + resourceRequirements.maxSlots.merge(requirements.maxSlots); descriptorPools->reserve(requirements); + + return result; } ref_ptr Context::allocateDescriptorSet(DescriptorSetLayout* descriptorSetLayout) diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index 653d7f9c6c..d9b6088703 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -206,23 +206,50 @@ bool Device::supportsDeviceExtension(const char* extensionName) const return (std::find_if(enabledExtensions.begin(), enabledExtensions.end(), compare) != enabledExtensions.end()); } -VkDeviceSize Device::availableMemory() const +VkDeviceSize Device::availableMemory(bool includeMemoryPools) const { VkDeviceSize available = 0; -#if 0 + VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; memoryBudget.pNext = nullptr; - VkPhysicalDeviceMemoryProperties2 memoryProperties; - memoryProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; - memoryProperties.pNext = &memoryBudget; + VkPhysicalDeviceMemoryProperties2 dmp; + dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + dmp.pNext = &memoryBudget; - vkGetPhysicalDeviceMemoryProperties2(*(device->getPhysicalDevice()), &memoryProperties); -#endif - if (auto pool = deviceMemoryBufferPools.ref_ptr()) + vkGetPhysicalDeviceMemoryProperties2(*(getPhysicalDevice()), &dmp); + + auto& memoryProperties = dmp.memoryProperties; + + VkMemoryPropertyFlags requiredPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + std::set compatibleHeaps; + for(uint32_t i=0; icomputeMemoryTotalAvailable(); + VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; + if (heapAvailable > minimumMargin) + { + available += (heapAvailable - minimumMargin); + } + } + + if (includeMemoryPools) + { + if (auto pool = deviceMemoryBufferPools.ref_ptr()) + { + available += pool->computeMemoryTotalAvailable(); + } } return available; diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index 168aacb9e7..eb34d8e716 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -74,7 +74,7 @@ VkDeviceSize MemoryBufferPools::computeBufferTotalReserved() const return totalReservedSize; } -ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkDeviceSize alignment, VkBufferUsageFlags bufferUsageFlags, VkSharingMode sharingMode, VkMemoryPropertyFlags memoryProperties) +ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkDeviceSize alignment, VkBufferUsageFlags bufferUsageFlags, VkSharingMode sharingMode, VkMemoryPropertyFlags memoryPropertiesFlags) { ref_ptr bufferInfo = BufferInfo::create(); @@ -106,11 +106,6 @@ ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkD //debug(name, " : Created new Buffer ", bufferInfo->buffer.get(), " totalSize ", totalSize, " deviceSize = ", deviceSize); - if (!bufferInfo->buffer->full()) - { - //debug(name, " inserting new Buffer into Context.bufferPools"); - bufferPools.push_back(bufferInfo->buffer); - } } //debug(name, " : bufferInfo->offset = ", bufferInfo->offset); @@ -118,26 +113,36 @@ ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkD VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(*device, bufferInfo->buffer->vk(device->deviceID), &memRequirements); - auto reservedMemorySlot = reserveMemory(memRequirements, memoryProperties); + auto reservedMemorySlot = reserveMemory(memRequirements, memoryPropertiesFlags); if (!reservedMemorySlot.first) { - //debug(name, " : Completely Failed to space for MemoryBufferPools::reserveBuffer(", totalSize, ", ", alignment, ", ", bufferUsageFlags, ") "); + info(name, " : Completely Failed to space for MemoryBufferPools::reserveBuffer(", totalSize, ", ", alignment, ", ", bufferUsageFlags, ")"); + //throw Exception{"Error: Failed to allocate Buffer from MemoryBufferPool.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; return {}; } //debug(name, " : Allocated new buffer, MemoryBufferPools::reserveBuffer(", totalSize, ", ", alignment, ", ", bufferUsageFlags, ") "); bufferInfo->buffer->bind(reservedMemorySlot.first, reservedMemorySlot.second); + //if (!bufferInfo->buffer->full()) + { + std::scoped_lock lock(_mutex); + //debug(name, " inserting new Buffer into Context.bufferPools"); + bufferPools.push_back(bufferInfo->buffer); + } + return bufferInfo; } -MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryRequirements memRequirements, VkMemoryPropertyFlags memoryProperties, void* pNextAllocInfo) +MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryRequirements memRequirements, VkMemoryPropertyFlags memoryPropertiesFlags, void* pNextAllocInfo) { + VkDeviceSize totalSize = memRequirements.size; + // vsg::info("MemoryBufferPools::reserveMemory() ", totalSize, ", device->availableMemory() = ", device->availableMemory()); + std::scoped_lock lock(_mutex); ref_ptr deviceMemory; - VkDeviceSize totalSize = memRequirements.size; MemorySlots::OptionalOffset reservedSlot(false, 0); for (auto& memoryPool : memoryPools) @@ -157,39 +162,179 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR if (!deviceMemory) { - VkDeviceSize deviceMemorySize = std::max(totalSize, minimumDeviceMemorySize); + VkDeviceSize availableSpace = std::max(minimumDeviceMemorySize, totalSize); + +#if 1 + VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; + memoryBudget.pNext = nullptr; - // clamp to an aligned size - deviceMemorySize = ((deviceMemorySize + memRequirements.alignment - 1) / memRequirements.alignment) * memRequirements.alignment; + VkPhysicalDeviceMemoryProperties2 dmp; + dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + dmp.pNext = &memoryBudget; - //debug("Creating new local DeviceMemory"); - if (memRequirements.size < deviceMemorySize) memRequirements.size = deviceMemorySize; + vkGetPhysicalDeviceMemoryProperties2(*(device->getPhysicalDevice()), &dmp); - deviceMemory = vsg::DeviceMemory::create(device, memRequirements, memoryProperties, pNextAllocInfo); - if (deviceMemory) + auto& memoryProperties = dmp.memoryProperties; + + uint32_t heapIndex = 0; + for(uint32_t i=0; ireserve(totalSize); - if (!deviceMemory->full()) + if ((memoryProperties.memoryTypes[i].propertyFlags & memoryPropertiesFlags) == memoryPropertiesFlags) // supported { - //debug(" inserting DeviceMemory into memoryPool ", deviceMemory.get()); - memoryPools.push_back(deviceMemory); + heapIndex = memoryProperties.memoryTypes[i].heapIndex; + VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; + availableSpace = heapAvailable; + break; } } - } - else - { - if (deviceMemory->full()) + + VkDeviceSize minimumSpare = 0;//16*1024*1024; + if (availableSpace < minimumSpare) availableSpace = 0; + else availableSpace -= minimumSpare; +#endif + + if (totalSize <= availableSpace) { - //debug("DeviceMemory is full ", deviceMemory.get()); + if (availableSpace < minimumDeviceMemorySize) + { + info("Reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); + minimumDeviceMemorySize = availableSpace; + } + + VkDeviceSize deviceMemorySize = std::max(totalSize, minimumDeviceMemorySize); + + // clamp to an aligned size + deviceMemorySize = ((deviceMemorySize + memRequirements.alignment - 1) / memRequirements.alignment) * memRequirements.alignment; + + //debug("Creating new local DeviceMemory"); + if (memRequirements.size < deviceMemorySize) memRequirements.size = deviceMemorySize; + + deviceMemory = vsg::DeviceMemory::create(device, memRequirements, memoryPropertiesFlags, pNextAllocInfo); + if (deviceMemory) + { + reservedSlot = deviceMemory->reserve(totalSize); + // if (!deviceMemory->full()) + { + //debug(" inserting DeviceMemory into memoryPool ", deviceMemory.get()); + memoryPools.push_back(deviceMemory); + } + } + else + { + info("MemoryBufferPools::reserveMemory() A Unsufficent availableSpace = ", availableSpace, ", for totalSize = ", totalSize); + } + } + else + { + info("MemoryBufferPools::reserveMemory() B Unsufficent availableSpace = ", availableSpace, ", for totalSize = ", totalSize); } } if (!reservedSlot.first) { - //debug("MemoryBufferPools::reserveMemory() Failed to reserve slot"); + info("MemoryBufferPools::reserveMemory() about to throw exception"); + //throw Exception{"Error: Failed to allocate DeviceMemory from MemoryBufferPool.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; return {}; } //debug("MemoryBufferPools::reserveMemory() allocated DeviceMemoryOffset(", deviceMemory, ", ", reservedSlot.second, ")"); return MemoryBufferPools::DeviceMemoryOffset(deviceMemory, reservedSlot.second); } + +VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) +{ + //vsg::info("MemoryBufferPools::reserve(ResourceRequirements& requirements) { "); + + auto deviceID = device->deviceID; + auto& limits = device->getPhysicalDevice()->getProperties().limits; + + VkMemoryPropertyFlags memoryPropertiesFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + // allocate bufferInfos + VkDeviceSize failedBufferMemory = 0; + for(auto& [properties, bufferInfos] : requirements.bufferInfos) + { + for(auto& bufferInfo : bufferInfos) + { + if (!bufferInfo->buffer) + { + VkDeviceSize alignment = 4; + if ((properties.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) alignment = limits.minUniformBufferOffsetAlignment; + else if ((properties.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) alignment = limits.minStorageBufferOffsetAlignment; + + auto newBufferInfo = reserveBuffer(bufferInfo->data->dataSize(), alignment, properties.usageFlags, properties.sharingMode, memoryPropertiesFlags); + if (newBufferInfo) + { + bufferInfo->buffer = newBufferInfo->buffer; + bufferInfo->offset = newBufferInfo->offset; + bufferInfo->range = newBufferInfo->range; + + newBufferInfo->release(); + + //info(" ALLOCATED usage = ", properties.usageFlags, ", alignment = ", alignment, ", bufferInfo->data = ", bufferInfo->data, ", offset = ", bufferInfo->offset, ", range = ", bufferInfo->range, ", buffer = ", bufferInfo->buffer, " ----- size = ", computeSize(*bufferInfo)); + } + else + { + failedBufferMemory += bufferInfo->data->dataSize(); + + //info(" FAILED to allocate bufferInfo->data = ", bufferInfo->data, ", offset = ", bufferInfo->offset, ", range = ", bufferInfo->range, ", buffer = ", bufferInfo->buffer, " ----- size = ", computeSize(*bufferInfo)); + } + } + } + } + + // allocate images + VkDeviceSize failedImageMemory = 0; + for(auto& imageInfo : requirements.imageInfos) + { + if (imageInfo->imageView && imageInfo->imageView->image && imageInfo->imageView->image->getDeviceMemory(deviceID) == 0) + { + if (imageInfo->imageView->image->compile(*this) == VK_SUCCESS && imageInfo->imageView->image->getDeviceMemory(deviceID) != 0) + { + //info(" ALLOCATED imageInfo = ", imageInfo, ", imageView = ", imageInfo->imageView, " ----- size = ", computeSize(*imageInfo), " device memory = ", imageInfo->imageView->image->getDeviceMemory(deviceID), " offset = ", imageInfo->imageView->image->getMemoryOffset(deviceID)); + } + else + { + failedImageMemory += computeSize(*imageInfo); + //info(" FAILED to allocate imageInfo = ", imageInfo, " ----- size = ", computeSize(*imageInfo)); + } + } + } + + + VkDeviceSize memoryRequired = failedBufferMemory + failedImageMemory; + + // all required resources allocated + if (memoryRequired == 0) + { + //info("MemoryBufferPools::reserve() memoryRequired = ", memoryRequired); + return VK_SUCCESS; + } + else + { + //VkDeviceSize memoryAvailable = device->availableMemory(false); + //info("MemoryBufferPools::reserve() out of memory: memoryAvailable = ", memoryAvailable, " memoryRequired = ", memoryRequired); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } +} + +VkDeviceSize MemoryBufferPools::computeSize(BufferInfo& bufferInfo) const +{ + return (bufferInfo.data) ? bufferInfo.data->dataSize(): 0; +} + +VkDeviceSize MemoryBufferPools::computeSize(ImageInfo& imageInfo) const +{ + if (imageInfo.imageView && imageInfo.imageView->image) + { + auto& image = imageInfo.imageView->image; + + // VkExtent3D extent = {0, 0, 0}; + // uint32_t mipLevels = 0; + // uint32_t arrayLayers = 0; + + if (image->data) return image->data->computeValueCountIncludingMipmaps(); + } + return 0; +} diff --git a/src/vsg/vk/ResourceRequirements.cpp b/src/vsg/vk/ResourceRequirements.cpp index d7cd9842c3..6034c06979 100644 --- a/src/vsg/vk/ResourceRequirements.cpp +++ b/src/vsg/vk/ResourceRequirements.cpp @@ -22,6 +22,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include +#include +#include #include #include #include @@ -46,6 +49,7 @@ ResourceRequirements::ResourceRequirements(ref_ptr hints) : if (hints) apply(*hints); } + uint32_t ResourceRequirements::computeNumDescriptorSets() const { return externalNumDescriptorSets + static_cast(descriptorSets.size()); @@ -130,7 +134,7 @@ bool CollectResourceRequirements::checkForResourceHints(const Object& object) if (resourceHints) { apply(*resourceHints); - return resourceHints->noTraverseBelowResourceHints; + return false;//resourceHints->noTraverseBelowResourceHints; } else { @@ -205,8 +209,27 @@ void CollectResourceRequirements::apply(const DescriptorBuffer& descriptorBuffer { if (registerDescriptor(descriptorBuffer)) { + BufferProperties properties; + + switch (descriptorBuffer.descriptorType) + { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + properties.usageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + properties.usageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + break; + default: + break; + } + + properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + properties.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + //info("CollectResourceRequirements::apply(const DescriptorBuffer& descriptorBuffer) ", &descriptorBuffer); - for (const auto& bufferInfo : descriptorBuffer.bufferInfoList) apply(bufferInfo); + for (const auto& bufferInfo : descriptorBuffer.bufferInfoList) apply(bufferInfo, properties); } } @@ -288,45 +311,98 @@ void CollectResourceRequirements::apply(const Bin& bin) void CollectResourceRequirements::apply(const Geometry& geometry) { - for (const auto& bufferInfo : geometry.arrays) apply(bufferInfo); - apply(geometry.indices); + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (geometry.indices) properties.usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + + for (const auto& bufferInfo : geometry.arrays) apply(bufferInfo, properties); + + if (geometry.indices) apply(geometry.indices, properties); } void CollectResourceRequirements::apply(const VertexDraw& vd) { - for (const auto& bufferInfo : vd.arrays) apply(bufferInfo); + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + for (const auto& bufferInfo : vd.arrays) apply(bufferInfo, properties); } void CollectResourceRequirements::apply(const VertexIndexDraw& vid) { - for (const auto& bufferInfo : vid.arrays) apply(bufferInfo); - apply(vid.indices); + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + for (const auto& bufferInfo : vid.arrays) apply(bufferInfo, properties); + apply(vid.indices, properties); +} + +void CollectResourceRequirements::apply(const InstanceNode& in) +{ + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + if (in.translations) apply(in.translations, properties); + if (in.rotations) apply(in.rotations, properties); + if (in.scales) apply(in.scales, properties); + if (in.colors) apply(in.colors, properties); + + in.traverse(*this); +} + +void CollectResourceRequirements::apply(const InstanceDraw& id) +{ + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + for (const auto& bufferInfo : id.arrays) apply(bufferInfo, properties); +} + +void CollectResourceRequirements::apply(const InstanceDrawIndexed& idi) +{ + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + for (const auto& bufferInfo : idi.arrays) apply(bufferInfo, properties); + apply(idi.indices, properties); } void CollectResourceRequirements::apply(const BindVertexBuffers& bvb) { - for (const auto& bufferInfo : bvb.arrays) apply(bufferInfo); + BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + for (const auto& bufferInfo : bvb.arrays) apply(bufferInfo, properties); } void CollectResourceRequirements::apply(const BindIndexBuffer& bib) { - apply(bib.indices); + BufferProperties properties{VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; + if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + apply(bib.indices, properties); } -void CollectResourceRequirements::apply(ref_ptr bufferInfo) +void CollectResourceRequirements::apply(ref_ptr bufferInfo, BufferProperties bufferProperties) { - if (bufferInfo && requirements.bufferInfos.count(bufferInfo)==0) + if (bufferInfo) { - requirements.bufferInfos.insert(bufferInfo); + if (bufferInfo->data && bufferInfo->data->dynamic()) bufferProperties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - if (bufferInfo->data) + auto& bufferInfos = requirements.bufferInfos[bufferProperties]; + if (bufferInfos.count(bufferInfo)==0) { - if (bufferInfo->data->dynamic()) + bufferInfos.insert(bufferInfo); + + if (bufferInfo->data) { - requirements.dynamicData.bufferInfos.push_back(bufferInfo); - } + if (bufferInfo->data->dynamic()) + { + requirements.dynamicData.bufferInfos.push_back(bufferInfo); + } - requirements.bufferMemoryRequirements += bufferInfo->data->dataSize(); + requirements.bufferMemoryRequirements += bufferInfo->data->dataSize(); + } } } } @@ -351,5 +427,9 @@ void CollectResourceRequirements::apply(ref_ptr imageInfo) requirements.imageMemoryRequirements += data->dataSize(); } } + else + { + vsg::debug("CollectResourceRequirements::apply() problem ImageInfo ", imageInfo, " { ", imageInfo->imageView, "}"); + } } } From af14d89a7c373eac3bcede7d91a85f79bcce3283 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Jan 2026 10:29:57 +0000 Subject: [PATCH 05/15] Removed no longer used member variables --- include/vsg/state/ResourceHints.h | 3 --- include/vsg/vk/ResourceRequirements.h | 3 --- src/vsg/state/ResourceHints.cpp | 6 ------ src/vsg/vk/ResourceRequirements.cpp | 8 -------- 4 files changed, 20 deletions(-) diff --git a/include/vsg/state/ResourceHints.h b/include/vsg/state/ResourceHints.h index 614fb4ab71..4e76b1641d 100644 --- a/include/vsg/state/ResourceHints.h +++ b/include/vsg/state/ResourceHints.h @@ -78,9 +78,6 @@ namespace vsg DataTransferHint dataTransferHint = COMPILE_TRAVERSAL_USE_TRANSFER_TASK; uint32_t viewportStateHint = DYNAMIC_VIEWPORTSTATE; - VkDeviceSize bufferMemoryRequirements = 0; - VkDeviceSize imageMemoryRequirements = 0; - DynamicData dynamicData; bool containsPagedLOD = false; diff --git a/include/vsg/vk/ResourceRequirements.h b/include/vsg/vk/ResourceRequirements.h index 66bc596f2e..1e9eabc4db 100644 --- a/include/vsg/vk/ResourceRequirements.h +++ b/include/vsg/vk/ResourceRequirements.h @@ -83,9 +83,6 @@ namespace vsg std::map>> bufferInfos; std::set> imageInfos; - VkDeviceSize bufferMemoryRequirements = 0; - VkDeviceSize imageMemoryRequirements = 0; - VkDeviceSize minimumBufferSize = 16 * 1024 * 1024; VkDeviceSize minimumDeviceMemorySize = 16 * 1024 * 1024; diff --git a/src/vsg/state/ResourceHints.cpp b/src/vsg/state/ResourceHints.cpp index ff9052c635..d6e028917e 100644 --- a/src/vsg/state/ResourceHints.cpp +++ b/src/vsg/state/ResourceHints.cpp @@ -77,9 +77,6 @@ void ResourceHints::read(Input& input) if (input.version_greater_equal(1, 1, 14)) { - input.read("bufferMemoryRequirements", bufferMemoryRequirements); - input.read("imageMemoryRequirements", imageMemoryRequirements); - input.readObjects("dynamicData.bufferInfos", dynamicData.bufferInfos); input.readObjects("dynamicData.imageInfos", dynamicData.imageInfos); @@ -143,9 +140,6 @@ void ResourceHints::write(Output& output) const if (output.version_greater_equal(1, 1, 14)) { - output.write("bufferMemoryRequirements", bufferMemoryRequirements); - output.write("imageMemoryRequirements", imageMemoryRequirements); - output.writeObjects("dynamicData.bufferInfos", dynamicData.bufferInfos); output.writeObjects("dynamicData.imageInfos", dynamicData.imageInfos); diff --git a/src/vsg/vk/ResourceRequirements.cpp b/src/vsg/vk/ResourceRequirements.cpp index 6034c06979..a18b882740 100644 --- a/src/vsg/vk/ResourceRequirements.cpp +++ b/src/vsg/vk/ResourceRequirements.cpp @@ -90,8 +90,6 @@ void ResourceRequirements::apply(const ResourceHints& resourceHints) dataTransferHint = resourceHints.dataTransferHint; viewportStateHint = resourceHints.viewportStateHint; - bufferMemoryRequirements += resourceHints.bufferMemoryRequirements; - imageMemoryRequirements += resourceHints.imageMemoryRequirements; dynamicData.add(resourceHints.dynamicData); containsPagedLOD = containsPagedLOD | resourceHints.containsPagedLOD; } @@ -113,8 +111,6 @@ ref_ptr CollectResourceRequirements::createResourceHints(uint32_t poolSize.descriptorCount = poolSize.descriptorCount * tileMultiplier; } - resourceHints->bufferMemoryRequirements = requirements.bufferMemoryRequirements; - resourceHints->imageMemoryRequirements = requirements.imageMemoryRequirements; resourceHints->dynamicData = requirements.dynamicData; resourceHints->containsPagedLOD = requirements.containsPagedLOD; @@ -400,8 +396,6 @@ void CollectResourceRequirements::apply(ref_ptr bufferInfo, BufferPr { requirements.dynamicData.bufferInfos.push_back(bufferInfo); } - - requirements.bufferMemoryRequirements += bufferInfo->data->dataSize(); } } } @@ -423,8 +417,6 @@ void CollectResourceRequirements::apply(ref_ptr imageInfo) { requirements.dynamicData.imageInfos.push_back(imageInfo); } - - requirements.imageMemoryRequirements += data->dataSize(); } } else From 0370c2b735594b810629e02304e4751d7d2c3480 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Jan 2026 11:06:58 +0000 Subject: [PATCH 06/15] Ran clang-format and removed no longer required include --- include/vsg/app/CompileManager.h | 1 - include/vsg/state/ResourceHints.h | 2 +- include/vsg/vk/ResourceRequirements.h | 2 +- src/vsg/io/DatabasePager.cpp | 2 +- src/vsg/nodes/PagedLOD.cpp | 1 - src/vsg/state/BufferInfo.cpp | 3 ++- src/vsg/state/Image.cpp | 2 +- src/vsg/state/ImageView.cpp | 2 +- src/vsg/vk/Device.cpp | 8 ++++---- src/vsg/vk/MemoryBufferPools.cpp | 28 ++++++++++++++------------ src/vsg/vk/ResourceRequirements.cpp | 29 +++++++++++++-------------- 11 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/vsg/app/CompileManager.h b/include/vsg/app/CompileManager.h index c437a71c2d..dff3c9f905 100644 --- a/include/vsg/app/CompileManager.h +++ b/include/vsg/app/CompileManager.h @@ -72,7 +72,6 @@ namespace vsg CompileResult compileTask(ref_ptr task, const ResourceRequirements& resourceRequirements = {}); protected: - using CompileTraversals = ThreadSafeQueue>; size_t numCompileTraversals = 0; ref_ptr compileTraversals; diff --git a/include/vsg/state/ResourceHints.h b/include/vsg/state/ResourceHints.h index 4e76b1641d..8ad59c3f4d 100644 --- a/include/vsg/state/ResourceHints.h +++ b/include/vsg/state/ResourceHints.h @@ -13,9 +13,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include -#include #include #include +#include namespace vsg { diff --git a/include/vsg/vk/ResourceRequirements.h b/include/vsg/vk/ResourceRequirements.h index 1e9eabc4db..8f23fbed8f 100644 --- a/include/vsg/vk/ResourceRequirements.h +++ b/include/vsg/vk/ResourceRequirements.h @@ -77,7 +77,7 @@ namespace vsg VkBufferUsageFlags usageFlags = 0; VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bool operator < (const BufferProperties& rhs) const { return (usageFlags < rhs.usageFlags) || ((usageFlags == rhs.usageFlags) && (sharingMode < rhs.sharingMode)); } + bool operator<(const BufferProperties& rhs) const { return (usageFlags < rhs.usageFlags) || ((usageFlags == rhs.usageFlags) && (sharingMode < rhs.sharingMode)); } }; std::map>> bufferInfos; diff --git a/src/vsg/io/DatabasePager.cpp b/src/vsg/io/DatabasePager.cpp index 1627be9531..ee7527b172 100644 --- a/src/vsg/io/DatabasePager.cpp +++ b/src/vsg/io/DatabasePager.cpp @@ -531,7 +531,7 @@ void DatabasePager::start(uint32_t numReadThreads) databasePager.requestDiscarded(plod); } } - catch(...) + catch (...) { debug("DatabaserPager::start() compile threw exception, discarding request ", subgraph); databasePager.requestDiscarded(plod); diff --git a/src/vsg/nodes/PagedLOD.cpp b/src/vsg/nodes/PagedLOD.cpp index 21e72c3caa..2b00a5b878 100644 --- a/src/vsg/nodes/PagedLOD.cpp +++ b/src/vsg/nodes/PagedLOD.cpp @@ -91,4 +91,3 @@ void PagedLOD::write(Output& output) const output.write("child.minimumScreenHeightRatio", children[1].minimumScreenHeightRatio); output.write("child.node", children[1].node); } - diff --git a/src/vsg/state/BufferInfo.cpp b/src/vsg/state/BufferInfo.cpp index c4961cb055..9cb3db10aa 100644 --- a/src/vsg/state/BufferInfo.cpp +++ b/src/vsg/state/BufferInfo.cpp @@ -256,7 +256,8 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu vkGetBufferMemoryRequirements(*device, deviceBufferInfo->buffer->vk(device->deviceID), &memRequirements); auto deviceMemoryOffset = context.deviceMemoryBufferPools->reserveMemory(memRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - if (!deviceMemoryOffset.first) deviceBufferInfo->buffer->bind(deviceMemoryOffset.first, deviceMemoryOffset.second); + if (!deviceMemoryOffset.first) + deviceBufferInfo->buffer->bind(deviceMemoryOffset.first, deviceMemoryOffset.second); else { info("vsg::createBufferAndTransferData() Failure to assign memory to existing BufferInfo"); diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 90ef0db414..7b3c51734a 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -232,7 +232,7 @@ VkResult Image::compile(Context& context) { return compile(*context.deviceMemoryBufferPools); } - catch(...) + catch (...) { vsg::info("Image::compile(Context& context)"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index de103cb00a..e8d8a722ea 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -14,7 +14,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include + using namespace vsg; VkImageAspectFlags vsg::computeAspectFlagsForFormat(VkFormat format) diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index d9b6088703..c539bfc3fa 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -211,7 +211,7 @@ VkDeviceSize Device::availableMemory(bool includeMemoryPools) const VkDeviceSize available = 0; VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; - memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; memoryBudget.pNext = nullptr; VkPhysicalDeviceMemoryProperties2 dmp; @@ -225,7 +225,7 @@ VkDeviceSize Device::availableMemory(bool includeMemoryPools) const VkMemoryPropertyFlags requiredPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; std::set compatibleHeaps; - for(uint32_t i=0; i minimumMargin) diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index eb34d8e716..c374e29433 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -105,7 +105,6 @@ ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkD bufferInfo->range = totalSize; //debug(name, " : Created new Buffer ", bufferInfo->buffer.get(), " totalSize ", totalSize, " deviceSize = ", deviceSize); - } //debug(name, " : bufferInfo->offset = ", bufferInfo->offset); @@ -166,7 +165,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR #if 1 VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; - memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; memoryBudget.pNext = nullptr; VkPhysicalDeviceMemoryProperties2 dmp; @@ -178,7 +177,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR auto& memoryProperties = dmp.memoryProperties; uint32_t heapIndex = 0; - for(uint32_t i=0; ibuffer) { VkDeviceSize alignment = 4; - if ((properties.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) alignment = limits.minUniformBufferOffsetAlignment; - else if ((properties.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) alignment = limits.minStorageBufferOffsetAlignment; + if ((properties.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0) + alignment = limits.minUniformBufferOffsetAlignment; + else if ((properties.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) + alignment = limits.minStorageBufferOffsetAlignment; auto newBufferInfo = reserveBuffer(bufferInfo->data->dataSize(), alignment, properties.usageFlags, properties.sharingMode, memoryPropertiesFlags); if (newBufferInfo) @@ -286,7 +289,7 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) // allocate images VkDeviceSize failedImageMemory = 0; - for(auto& imageInfo : requirements.imageInfos) + for (auto& imageInfo : requirements.imageInfos) { if (imageInfo->imageView && imageInfo->imageView->image && imageInfo->imageView->image->getDeviceMemory(deviceID) == 0) { @@ -302,7 +305,6 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) } } - VkDeviceSize memoryRequired = failedBufferMemory + failedImageMemory; // all required resources allocated @@ -321,7 +323,7 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) VkDeviceSize MemoryBufferPools::computeSize(BufferInfo& bufferInfo) const { - return (bufferInfo.data) ? bufferInfo.data->dataSize(): 0; + return (bufferInfo.data) ? bufferInfo.data->dataSize() : 0; } VkDeviceSize MemoryBufferPools::computeSize(ImageInfo& imageInfo) const diff --git a/src/vsg/vk/ResourceRequirements.cpp b/src/vsg/vk/ResourceRequirements.cpp index a18b882740..c4fe94a5ea 100644 --- a/src/vsg/vk/ResourceRequirements.cpp +++ b/src/vsg/vk/ResourceRequirements.cpp @@ -17,14 +17,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include +#include +#include #include #include #include #include #include -#include -#include -#include #include #include #include @@ -49,7 +49,6 @@ ResourceRequirements::ResourceRequirements(ref_ptr hints) : if (hints) apply(*hints); } - uint32_t ResourceRequirements::computeNumDescriptorSets() const { return externalNumDescriptorSets + static_cast(descriptorSets.size()); @@ -130,7 +129,7 @@ bool CollectResourceRequirements::checkForResourceHints(const Object& object) if (resourceHints) { apply(*resourceHints); - return false;//resourceHints->noTraverseBelowResourceHints; + return false; //resourceHints->noTraverseBelowResourceHints; } else { @@ -308,7 +307,7 @@ void CollectResourceRequirements::apply(const Bin& bin) void CollectResourceRequirements::apply(const Geometry& geometry) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; if (geometry.indices) properties.usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; for (const auto& bufferInfo : geometry.arrays) apply(bufferInfo, properties); @@ -319,7 +318,7 @@ void CollectResourceRequirements::apply(const Geometry& geometry) void CollectResourceRequirements::apply(const VertexDraw& vd) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; for (const auto& bufferInfo : vd.arrays) apply(bufferInfo, properties); } @@ -327,7 +326,7 @@ void CollectResourceRequirements::apply(const VertexDraw& vd) void CollectResourceRequirements::apply(const VertexIndexDraw& vid) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; for (const auto& bufferInfo : vid.arrays) apply(bufferInfo, properties); apply(vid.indices, properties); @@ -336,7 +335,7 @@ void CollectResourceRequirements::apply(const VertexIndexDraw& vid) void CollectResourceRequirements::apply(const InstanceNode& in) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; if (in.translations) apply(in.translations, properties); if (in.rotations) apply(in.rotations, properties); @@ -349,7 +348,7 @@ void CollectResourceRequirements::apply(const InstanceNode& in) void CollectResourceRequirements::apply(const InstanceDraw& id) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; for (const auto& bufferInfo : id.arrays) apply(bufferInfo, properties); } @@ -357,7 +356,7 @@ void CollectResourceRequirements::apply(const InstanceDraw& id) void CollectResourceRequirements::apply(const InstanceDrawIndexed& idi) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; for (const auto& bufferInfo : idi.arrays) apply(bufferInfo, properties); apply(idi.indices, properties); @@ -366,7 +365,7 @@ void CollectResourceRequirements::apply(const InstanceDrawIndexed& idi) void CollectResourceRequirements::apply(const BindVertexBuffers& bvb) { BufferProperties properties{VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; for (const auto& bufferInfo : bvb.arrays) apply(bufferInfo, properties); } @@ -374,7 +373,7 @@ void CollectResourceRequirements::apply(const BindVertexBuffers& bvb) void CollectResourceRequirements::apply(const BindIndexBuffer& bib) { BufferProperties properties{VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE}; - if (requirements.dataTransferHint==COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + if (requirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) properties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; apply(bib.indices, properties); } @@ -386,7 +385,7 @@ void CollectResourceRequirements::apply(ref_ptr bufferInfo, BufferPr if (bufferInfo->data && bufferInfo->data->dynamic()) bufferProperties.usageFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; auto& bufferInfos = requirements.bufferInfos[bufferProperties]; - if (bufferInfos.count(bufferInfo)==0) + if (bufferInfos.count(bufferInfo) == 0) { bufferInfos.insert(bufferInfo); @@ -403,7 +402,7 @@ void CollectResourceRequirements::apply(ref_ptr bufferInfo, BufferPr void CollectResourceRequirements::apply(ref_ptr imageInfo) { - if (imageInfo && requirements.imageInfos.count(imageInfo)==0) + if (imageInfo && requirements.imageInfos.count(imageInfo) == 0) { if (imageInfo->imageView && imageInfo->imageView->image) { From 03eb52a8d7f61e2f09f688c187d4ee3bfd35c17f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Jan 2026 12:51:02 +0000 Subject: [PATCH 07/15] Removed no longer required member variable and quietened down debug output --- include/vsg/state/ResourceHints.h | 3 --- src/vsg/state/BufferInfo.cpp | 4 ++-- src/vsg/state/ResourceHints.cpp | 4 ---- src/vsg/vk/MemoryBufferPools.cpp | 15 +++------------ src/vsg/vk/ResourceRequirements.cpp | 14 +++----------- 5 files changed, 8 insertions(+), 32 deletions(-) diff --git a/include/vsg/state/ResourceHints.h b/include/vsg/state/ResourceHints.h index 8ad59c3f4d..93afdba92c 100644 --- a/include/vsg/state/ResourceHints.h +++ b/include/vsg/state/ResourceHints.h @@ -82,9 +82,6 @@ namespace vsg bool containsPagedLOD = false; - /// hint whether CollectResourceRequirements visitor should traverse the subgraph below a node that has a "ResourceHints" assignd as meta data. - bool noTraverseBelowResourceHints = false; - public: void read(Input& input) override; void write(Output& output) const override; diff --git a/src/vsg/state/BufferInfo.cpp b/src/vsg/state/BufferInfo.cpp index 9cb3db10aa..ae52d2f64c 100644 --- a/src/vsg/state/BufferInfo.cpp +++ b/src/vsg/state/BufferInfo.cpp @@ -260,7 +260,7 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu deviceBufferInfo->buffer->bind(deviceMemoryOffset.first, deviceMemoryOffset.second); else { - info("vsg::createBufferAndTransferData() Failure to assign memory to existing BufferInfo"); + debug("vsg::createBufferAndTransferData() Failure to assign memory to existing BufferInfo"); return false; } } @@ -275,7 +275,7 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu if (!deviceBufferInfo) { - info("vsg::createBufferAndTransferData() Failure to assign Buffer"); + debug("vsg::createBufferAndTransferData() Failure to assign Buffer"); return false; } diff --git a/src/vsg/state/ResourceHints.cpp b/src/vsg/state/ResourceHints.cpp index d6e028917e..3e9f8dec67 100644 --- a/src/vsg/state/ResourceHints.cpp +++ b/src/vsg/state/ResourceHints.cpp @@ -81,8 +81,6 @@ void ResourceHints::read(Input& input) input.readObjects("dynamicData.imageInfos", dynamicData.imageInfos); input.read("containsPagedLOD", containsPagedLOD); - - input.read("noTraverseBelowResourceHints", noTraverseBelowResourceHints); } } @@ -144,7 +142,5 @@ void ResourceHints::write(Output& output) const output.writeObjects("dynamicData.imageInfos", dynamicData.imageInfos); output.write("containsPagedLOD", containsPagedLOD); - - output.write("noTraverseBelowResourceHints", noTraverseBelowResourceHints); } } diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index c374e29433..3aab048413 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -116,7 +116,7 @@ ref_ptr MemoryBufferPools::reserveBuffer(VkDeviceSize totalSize, VkD if (!reservedMemorySlot.first) { - info(name, " : Completely Failed to space for MemoryBufferPools::reserveBuffer(", totalSize, ", ", alignment, ", ", bufferUsageFlags, ")"); + debug(name, " : Failed to space for MemoryBufferPools::reserveBuffer(", totalSize, ", ", alignment, ", ", bufferUsageFlags, ")"); //throw Exception{"Error: Failed to allocate Buffer from MemoryBufferPool.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; return {}; } @@ -199,7 +199,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR { if (availableSpace < minimumDeviceMemorySize) { - info("Reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); + info("MemoryBufferPools::reserveMemory(", totalSize,") reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); minimumDeviceMemorySize = availableSpace; } @@ -221,21 +221,12 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR memoryPools.push_back(deviceMemory); } } - else - { - info("MemoryBufferPools::reserveMemory() A Unsufficent availableSpace = ", availableSpace, ", for totalSize = ", totalSize); - } - } - else - { - info("MemoryBufferPools::reserveMemory() B Unsufficent availableSpace = ", availableSpace, ", for totalSize = ", totalSize); } } if (!reservedSlot.first) { - info("MemoryBufferPools::reserveMemory() about to throw exception"); - //throw Exception{"Error: Failed to allocate DeviceMemory from MemoryBufferPool.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; + debug("MemoryBufferPools::reserveMemory(", totalSize,") failed, insufficient memory available."); return {}; } diff --git a/src/vsg/vk/ResourceRequirements.cpp b/src/vsg/vk/ResourceRequirements.cpp index c4fe94a5ea..6a5bb6ae76 100644 --- a/src/vsg/vk/ResourceRequirements.cpp +++ b/src/vsg/vk/ResourceRequirements.cpp @@ -113,8 +113,6 @@ ref_ptr CollectResourceRequirements::createResourceHints(uint32_t resourceHints->dynamicData = requirements.dynamicData; resourceHints->containsPagedLOD = requirements.containsPagedLOD; - resourceHints->noTraverseBelowResourceHints = true; - return resourceHints; } @@ -129,7 +127,7 @@ bool CollectResourceRequirements::checkForResourceHints(const Object& object) if (resourceHints) { apply(*resourceHints); - return false; //resourceHints->noTraverseBelowResourceHints; + return true; } else { @@ -144,10 +142,7 @@ void CollectResourceRequirements::apply(const ResourceHints& resourceHints) void CollectResourceRequirements::apply(const Node& node) { - if (checkForResourceHints(node)) - { - return; - } + checkForResourceHints(node); node.traverse(*this); } @@ -156,10 +151,7 @@ void CollectResourceRequirements::apply(const PagedLOD& plod) { requirements.containsPagedLOD = true; - if (checkForResourceHints(plod)) - { - return; - } + checkForResourceHints(plod); plod.traverse(*this); } From a0ff1192eebf05a4b536877179c30e0c77de5e20 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Jan 2026 17:13:03 +0000 Subject: [PATCH 08/15] Moved compute data size from MemoryBufferPools into BufferInfo/ImageInfo. --- include/vsg/state/BufferInfo.h | 3 +++ include/vsg/state/ImageInfo.h | 3 +++ include/vsg/vk/MemoryBufferPools.h | 3 --- src/vsg/state/BufferInfo.cpp | 6 ++++++ src/vsg/state/ImageInfo.cpp | 15 +++++++++++++++ src/vsg/vk/MemoryBufferPools.cpp | 27 ++------------------------- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/include/vsg/state/BufferInfo.h b/include/vsg/state/BufferInfo.h index 6d337b427d..b58ee63b13 100644 --- a/include/vsg/state/BufferInfo.h +++ b/include/vsg/state/BufferInfo.h @@ -38,6 +38,9 @@ namespace vsg void release(); + /// compute size of associated data + VkDeviceSize computeDataSize() const; + /// Copy data to the VkBuffer(s) for all Devices associated with vsg::Buffer /// Requires associated buffer memory to be host visible, for non host visible buffers you must use a staging buffer void copyDataToBuffer(); diff --git a/include/vsg/state/ImageInfo.h b/include/vsg/state/ImageInfo.h index afd8f857e6..7d26450186 100644 --- a/include/vsg/state/ImageInfo.h +++ b/include/vsg/state/ImageInfo.h @@ -47,6 +47,9 @@ namespace vsg ref_ptr imageView; VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + /// compute size of associated data + VkDeviceSize computeDataSize() const; + /// return true if the ImageInfo's data has been modified and should be copied to the buffer bool requiresCopy(uint32_t deviceID) const { diff --git a/include/vsg/vk/MemoryBufferPools.h b/include/vsg/vk/MemoryBufferPools.h index ca2e413346..77b442d933 100644 --- a/include/vsg/vk/MemoryBufferPools.h +++ b/include/vsg/vk/MemoryBufferPools.h @@ -46,9 +46,6 @@ namespace vsg VkResult reserve(ResourceRequirements& requirements); - VkDeviceSize computeSize(BufferInfo& bufferInfo) const; - VkDeviceSize computeSize(ImageInfo& imageInfo) const; - protected: mutable std::mutex _mutex; diff --git a/src/vsg/state/BufferInfo.cpp b/src/vsg/state/BufferInfo.cpp index ae52d2f64c..f579e6cff4 100644 --- a/src/vsg/state/BufferInfo.cpp +++ b/src/vsg/state/BufferInfo.cpp @@ -343,6 +343,12 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu return true; } + +VkDeviceSize BufferInfo::computeDataSize() const +{ + return data ? data->dataSize() : 0; +} + ///////////////////////////////////////////////////////////////////////////////////////// // // vsg::createHostVisibleBuffer diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 144edc9f94..72ec2a5e3f 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -414,3 +414,18 @@ void ImageInfo::computeNumMipMapLevels() if (generateMipmaps) image->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } } + +VkDeviceSize ImageInfo::computeDataSize() const +{ + if (imageView && imageView->image) + { + auto& image = imageView->image; + + // VkExtent3D extent = {0, 0, 0}; + // uint32_t mipLevels = 0; + // uint32_t arrayLayers = 0; + + if (image->data) return image->data->computeValueCountIncludingMipmaps(); + } + return 0; +} diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index 3aab048413..ffb732eb36 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -270,9 +270,7 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) } else { - failedBufferMemory += bufferInfo->data->dataSize(); - - //info(" FAILED to allocate bufferInfo->data = ", bufferInfo->data, ", offset = ", bufferInfo->offset, ", range = ", bufferInfo->range, ", buffer = ", bufferInfo->buffer, " ----- size = ", computeSize(*bufferInfo)); + failedBufferMemory += bufferInfo->computeDataSize(); } } } @@ -290,8 +288,7 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) } else { - failedImageMemory += computeSize(*imageInfo); - //info(" FAILED to allocate imageInfo = ", imageInfo, " ----- size = ", computeSize(*imageInfo)); + failedImageMemory += imageInfo->computeDataSize(); } } } @@ -311,23 +308,3 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) return VK_ERROR_OUT_OF_DEVICE_MEMORY; } } - -VkDeviceSize MemoryBufferPools::computeSize(BufferInfo& bufferInfo) const -{ - return (bufferInfo.data) ? bufferInfo.data->dataSize() : 0; -} - -VkDeviceSize MemoryBufferPools::computeSize(ImageInfo& imageInfo) const -{ - if (imageInfo.imageView && imageInfo.imageView->image) - { - auto& image = imageInfo.imageView->image; - - // VkExtent3D extent = {0, 0, 0}; - // uint32_t mipLevels = 0; - // uint32_t arrayLayers = 0; - - if (image->data) return image->data->computeValueCountIncludingMipmaps(); - } - return 0; -} From 57cd152222140308aa9cb535d2fe50b82b5a0da9 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 24 Jan 2026 17:13:47 +0000 Subject: [PATCH 09/15] Ran clang-format --- src/vsg/state/BufferInfo.cpp | 1 - src/vsg/vk/MemoryBufferPools.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vsg/state/BufferInfo.cpp b/src/vsg/state/BufferInfo.cpp index f579e6cff4..8f882c4156 100644 --- a/src/vsg/state/BufferInfo.cpp +++ b/src/vsg/state/BufferInfo.cpp @@ -343,7 +343,6 @@ bool vsg::createBufferAndTransferData(Context& context, const BufferInfoList& bu return true; } - VkDeviceSize BufferInfo::computeDataSize() const { return data ? data->dataSize() : 0; diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index ffb732eb36..fe261d770d 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -199,7 +199,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR { if (availableSpace < minimumDeviceMemorySize) { - info("MemoryBufferPools::reserveMemory(", totalSize,") reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); + info("MemoryBufferPools::reserveMemory(", totalSize, ") reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); minimumDeviceMemorySize = availableSpace; } @@ -226,7 +226,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR if (!reservedSlot.first) { - debug("MemoryBufferPools::reserveMemory(", totalSize,") failed, insufficient memory available."); + debug("MemoryBufferPools::reserveMemory(", totalSize, ") failed, insufficient memory available."); return {}; } From 0099cff072e27f2961643405e876c2e4476f1d95 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 25 Jan 2026 13:11:06 +0000 Subject: [PATCH 10/15] Simplified return code --- src/vsg/state/Image.cpp | 17 +++-------------- src/vsg/state/ImageInfo.cpp | 5 ----- src/vsg/vk/Device.cpp | 4 +--- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 7b3c51734a..c651fe70ef 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -228,15 +228,7 @@ VkResult Image::compile(Device* device) VkResult Image::compile(Context& context) { - try - { - return compile(*context.deviceMemoryBufferPools); - } - catch (...) - { - vsg::info("Image::compile(Context& context)"); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } + return compile(*context.deviceMemoryBufferPools); } VkResult Image::compile(MemoryBufferPools& memoryBufferPools) @@ -255,13 +247,10 @@ VkResult Image::compile(MemoryBufferPools& memoryBufferPools) if (deviceMemory) { vd.requiresDataCopy = data.valid(); - bind(deviceMemory, offset); + return bind(deviceMemory, offset); } else { - // throw Exception{"Error: Image failed to reserve slot from deviceMemoryBufferPools.", VK_ERROR_OUT_OF_DEVICE_MEMORY}; - result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - - return result; } diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 72ec2a5e3f..192cd980f1 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -420,11 +420,6 @@ VkDeviceSize ImageInfo::computeDataSize() const if (imageView && imageView->image) { auto& image = imageView->image; - - // VkExtent3D extent = {0, 0, 0}; - // uint32_t mipLevels = 0; - // uint32_t arrayLayers = 0; - if (image->data) return image->data->computeValueCountIncludingMipmaps(); } return 0; diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index c539bfc3fa..b3017f146f 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -233,14 +233,12 @@ VkDeviceSize Device::availableMemory(bool includeMemoryPools) const } } - VkDeviceSize minimumMargin = 0; //1024*1024*1024; - for (auto& heapIndex : compatibleHeaps) { VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; if (heapAvailable > minimumMargin) { - available += (heapAvailable - minimumMargin); + available += heapAvailable; } } From 7116470218f0ce0be8c865e608b9eb747e82654b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 25 Jan 2026 13:25:09 +0000 Subject: [PATCH 11/15] Fixed build error --- src/vsg/vk/Device.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index b3017f146f..d282b8c620 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -236,10 +236,7 @@ VkDeviceSize Device::availableMemory(bool includeMemoryPools) const for (auto& heapIndex : compatibleHeaps) { VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; - if (heapAvailable > minimumMargin) - { - available += heapAvailable; - } + available += heapAvailable; } if (includeMemoryPools) From c9d3ab39335b0329f5465c0846e1818dc8e59264 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 25 Jan 2026 18:38:42 +0000 Subject: [PATCH 12/15] Added MemoryBufferPools::allocatedMemoryLimit ratio to provide control over how much device memory can be used by application --- include/vsg/vk/MemoryBufferPools.h | 5 +++ src/vsg/vk/MemoryBufferPools.cpp | 53 ++++++++++++++++-------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/vsg/vk/MemoryBufferPools.h b/include/vsg/vk/MemoryBufferPools.h index 77b442d933..3ae8ab78bd 100644 --- a/include/vsg/vk/MemoryBufferPools.h +++ b/include/vsg/vk/MemoryBufferPools.h @@ -34,6 +34,11 @@ namespace vsg VkDeviceSize minimumBufferSize = 16 * 1024 * 1024; VkDeviceSize minimumDeviceMemorySize = 16 * 1024 * 1024; + /// Ratio of available device memory that can be allocated. + /// Ratios less than 1.0 require VK_EXT_memory_budget extension to be supported. + /// Ratio of 1.0 (or greater) will switch off checks for available memory and keep allocating till Vulkan memory allocations fail. + double allocatedMemoryLimit = 1.0; + VkDeviceSize computeMemoryTotalAvailable() const; VkDeviceSize computeMemoryTotalReserved() const; VkDeviceSize computeBufferTotalAvailable() const; diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index fe261d770d..d410655c13 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -163,37 +163,42 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR { VkDeviceSize availableSpace = std::max(minimumDeviceMemorySize, totalSize); -#if 1 - VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; - memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - memoryBudget.pNext = nullptr; + if (allocatedMemoryLimit < 1.0) + { + VkPhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget; + memoryBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; + memoryBudget.pNext = nullptr; - VkPhysicalDeviceMemoryProperties2 dmp; - dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; - dmp.pNext = &memoryBudget; + VkPhysicalDeviceMemoryProperties2 dmp; + dmp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + dmp.pNext = &memoryBudget; - vkGetPhysicalDeviceMemoryProperties2(*(device->getPhysicalDevice()), &dmp); + vkGetPhysicalDeviceMemoryProperties2(*(device->getPhysicalDevice()), &dmp); - auto& memoryProperties = dmp.memoryProperties; + auto& memoryProperties = dmp.memoryProperties; - uint32_t heapIndex = 0; - for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) - { - if ((memoryProperties.memoryTypes[i].propertyFlags & memoryPropertiesFlags) == memoryPropertiesFlags) // supported + uint32_t heapIndex = 0; + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { - heapIndex = memoryProperties.memoryTypes[i].heapIndex; - VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; - availableSpace = heapAvailable; - break; + if ((memoryProperties.memoryTypes[i].propertyFlags & memoryPropertiesFlags) == memoryPropertiesFlags) // supported + { + heapIndex = memoryProperties.memoryTypes[i].heapIndex; + + VkDeviceSize heapBudget = static_cast(static_cast(memoryBudget.heapBudget[heapIndex]) * allocatedMemoryLimit); + VkDeviceSize heapUsage = memoryBudget.heapUsage[heapIndex]; + VkDeviceSize heapAvailable = (heapUsage < heapBudget) ? heapBudget - heapUsage : 0; + availableSpace = heapAvailable; + + break; + } } - } - VkDeviceSize minimumSpare = 0; //16*1024*1024; - if (availableSpace < minimumSpare) - availableSpace = 0; - else - availableSpace -= minimumSpare; -#endif + VkDeviceSize minimumSpare = 0; //16*1024*1024; + if (availableSpace < minimumSpare) + availableSpace = 0; + else + availableSpace -= minimumSpare; + } if (totalSize <= availableSpace) { From df4f010f07004b6da1a9608571045e3b5a5b8fb9 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 26 Jan 2026 09:26:40 +0000 Subject: [PATCH 13/15] Fixed cppcheck reported issues --- src/vsg/state/ImageInfo.cpp | 2 +- src/vsg/vk/Device.cpp | 2 +- src/vsg/vk/MemoryBufferPools.cpp | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 192cd980f1..3d7e791dd4 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -419,7 +419,7 @@ VkDeviceSize ImageInfo::computeDataSize() const { if (imageView && imageView->image) { - auto& image = imageView->image; + const auto& image = imageView->image; if (image->data) return image->data->computeValueCountIncludingMipmaps(); } return 0; diff --git a/src/vsg/vk/Device.cpp b/src/vsg/vk/Device.cpp index d282b8c620..61f00211b5 100644 --- a/src/vsg/vk/Device.cpp +++ b/src/vsg/vk/Device.cpp @@ -233,7 +233,7 @@ VkDeviceSize Device::availableMemory(bool includeMemoryPools) const } } - for (auto& heapIndex : compatibleHeaps) + for (const auto& heapIndex : compatibleHeaps) { VkDeviceSize heapAvailable = memoryBudget.heapBudget[heapIndex] - memoryBudget.heapUsage[heapIndex]; available += heapAvailable; diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index d410655c13..b2f150404d 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -177,12 +177,11 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR auto& memoryProperties = dmp.memoryProperties; - uint32_t heapIndex = 0; for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { if ((memoryProperties.memoryTypes[i].propertyFlags & memoryPropertiesFlags) == memoryPropertiesFlags) // supported { - heapIndex = memoryProperties.memoryTypes[i].heapIndex; + uint32_t heapIndex = memoryProperties.memoryTypes[i].heapIndex; VkDeviceSize heapBudget = static_cast(static_cast(memoryBudget.heapBudget[heapIndex]) * allocatedMemoryLimit); VkDeviceSize heapUsage = memoryBudget.heapUsage[heapIndex]; @@ -244,7 +243,7 @@ VkResult MemoryBufferPools::reserve(ResourceRequirements& requirements) //vsg::info("MemoryBufferPools::reserve(ResourceRequirements& requirements) { "); auto deviceID = device->deviceID; - auto& limits = device->getPhysicalDevice()->getProperties().limits; + const auto& limits = device->getPhysicalDevice()->getProperties().limits; VkMemoryPropertyFlags memoryPropertiesFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; From fb63aa2e3b1e3be802c6a711e91401a73d3727b4 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 26 Jan 2026 14:52:05 +0000 Subject: [PATCH 14/15] Added allocatedMemoryLimit to ResourceHints and MemoryBufferPools to enable control over what raio of available heap memory on device is allocated by the VSG. Added MemoryBufferPools::throwOutOfDeviceMemoryException bool to control whether MemoryBufferPools::reserveMemory(..) should throw an vsg::Exception on failure to allocated memory from a vk/vsg::DeviceMemory --- include/vsg/app/Viewer.h | 2 +- include/vsg/state/ResourceHints.h | 5 ++++ include/vsg/vk/MemoryBufferPools.h | 3 +++ src/vsg/app/CompileManager.cpp | 40 ++++++++++++++++++++++-------- src/vsg/app/Viewer.cpp | 17 ++++++++++--- src/vsg/state/Image.cpp | 2 ++ src/vsg/state/ResourceHints.cpp | 2 ++ src/vsg/vk/MemoryBufferPools.cpp | 7 +++++- 8 files changed, 62 insertions(+), 16 deletions(-) diff --git a/include/vsg/app/Viewer.h b/include/vsg/app/Viewer.h index 4dd2eb2075..a2603e0daa 100644 --- a/include/vsg/app/Viewer.h +++ b/include/vsg/app/Viewer.h @@ -104,7 +104,7 @@ namespace vsg /// pass the Events into any registered EventHandlers virtual void handleEvents(); - virtual void compile(ref_ptr hints = {}); + virtual CompileResult compile(ref_ptr hints = {}); virtual bool acquireNextFrame(); diff --git a/include/vsg/state/ResourceHints.h b/include/vsg/state/ResourceHints.h index 93afdba92c..91fc704372 100644 --- a/include/vsg/state/ResourceHints.h +++ b/include/vsg/state/ResourceHints.h @@ -82,6 +82,11 @@ namespace vsg bool containsPagedLOD = false; + /// Ratio of available device memory that can be allocated. + /// Ratios less than 1.0 require VK_EXT_memory_budget extension to be supported. + /// Ratio of 1.0 (or greater) will switch off checks for available memory and keep allocating till Vulkan memory allocations fail. + double allocatedMemoryLimit = 1.0; + public: void read(Input& input) override; void write(Output& output) const override; diff --git a/include/vsg/vk/MemoryBufferPools.h b/include/vsg/vk/MemoryBufferPools.h index 3ae8ab78bd..320cf631bf 100644 --- a/include/vsg/vk/MemoryBufferPools.h +++ b/include/vsg/vk/MemoryBufferPools.h @@ -39,6 +39,9 @@ namespace vsg /// Ratio of 1.0 (or greater) will switch off checks for available memory and keep allocating till Vulkan memory allocations fail. double allocatedMemoryLimit = 1.0; + /// throw vsg::Exception when reserveMemory() fails to allocated memory on device. + bool throwOutOfDeviceMemoryException = true; + VkDeviceSize computeMemoryTotalAvailable() const; VkDeviceSize computeMemoryTotalReserved() const; VkDeviceSize computeBufferTotalAvailable() const; diff --git a/src/vsg/app/CompileManager.cpp b/src/vsg/app/CompileManager.cpp index 6c7f05db60..cdd28de2ad 100644 --- a/src/vsg/app/CompileManager.cpp +++ b/src/vsg/app/CompileManager.cpp @@ -256,25 +256,43 @@ CompileResult CompileManager::compile(ref_ptr object, ContextSelectionFu CompileResult CompileManager::compileTask(ref_ptr task, const ResourceRequirements& resourceRequirements) { - auto compileTraversal = CompileTraversal::create(task->device, resourceRequirements); + CompileResult result; + + // assume success, overwrite this on failures. + result.result = VK_SUCCESS; - for (const auto& context : compileTraversal->contexts) + try { - if (resourceRequirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) + auto compileTraversal = CompileTraversal::create(task->device, resourceRequirements); + + for (const auto& context : compileTraversal->contexts) { - context->transferTask = task->transferTask; + if (resourceRequirements.dataTransferHint == COMPILE_TRAVERSAL_USE_TRANSFER_TASK) + { + context->transferTask = task->transferTask; + } } - } - for (auto& cg : task->commandGraphs) + for (auto& cg : task->commandGraphs) + { + cg->accept(*compileTraversal); + } + + if (compileTraversal->record()) + { + compileTraversal->waitForCompletion(); + } + } + catch (const vsg::Exception& ve) { - cg->accept(*compileTraversal); + result.message = ve.message; + result.result = ve.result; } - - if (compileTraversal->record()) + catch (...) { - compileTraversal->waitForCompletion(); + result.message = "Exception occurred during compilation."; + result.result = VK_ERROR_UNKNOWN; } - return {}; + return result; } diff --git a/src/vsg/app/Viewer.cpp b/src/vsg/app/Viewer.cpp index 9d8374e924..07a599860f 100644 --- a/src/vsg/app/Viewer.cpp +++ b/src/vsg/app/Viewer.cpp @@ -275,15 +275,16 @@ void Viewer::handleEvents() } } -void Viewer::compile(ref_ptr hints) +CompileResult Viewer::compile(ref_ptr hints) { CPU_INSTRUMENTATION_L1_NC(instrumentation, "Viewer compile", COLOR_COMPILE); if (recordAndSubmitTasks.empty()) { - return; + return {}; } + CompileResult result; bool containsPagedLOD = false; ref_ptr databasePager; @@ -386,9 +387,17 @@ void Viewer::compile(ref_ptr hints) for (auto& task : recordAndSubmitTasks) { + if (hints) + { + if (auto deviceMemoryBufferPools = task->device->deviceMemoryBufferPools.ref_ptr()) + { + deviceMemoryBufferPools->allocatedMemoryLimit = hints->allocatedMemoryLimit; + } + } + auto& deviceResource = deviceResourceMap[task->device]; auto& resourceRequirements = deviceResource.collectResources.requirements; - compileManager->compileTask(task, resourceRequirements); + result.add(compileManager->compileTask(task, resourceRequirements)); task->transferTask->assign(resourceRequirements.dynamicData); } @@ -403,6 +412,8 @@ void Viewer::compile(ref_ptr hints) task->databasePager->start(); } } + + return result; } void Viewer::assignRecordAndSubmitTaskAndPresentation(CommandGraphs in_commandGraphs) diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index c651fe70ef..64d1564504 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -143,6 +143,8 @@ int Image::compare(const Object& rhs_object) const VkResult Image::bind(DeviceMemory* deviceMemory, VkDeviceSize memoryOffset) { + if (!deviceMemory) return VK_ERROR_OUT_OF_DEVICE_MEMORY; + VulkanData& vd = _vulkanData[deviceMemory->getDevice()->deviceID]; VkResult result = vkBindImageMemory(*vd.device, vd.image, *deviceMemory, memoryOffset); diff --git a/src/vsg/state/ResourceHints.cpp b/src/vsg/state/ResourceHints.cpp index 3e9f8dec67..9c05fe35de 100644 --- a/src/vsg/state/ResourceHints.cpp +++ b/src/vsg/state/ResourceHints.cpp @@ -81,6 +81,7 @@ void ResourceHints::read(Input& input) input.readObjects("dynamicData.imageInfos", dynamicData.imageInfos); input.read("containsPagedLOD", containsPagedLOD); + input.read("allocatedMemoryLimit", allocatedMemoryLimit); } } @@ -142,5 +143,6 @@ void ResourceHints::write(Output& output) const output.writeObjects("dynamicData.imageInfos", dynamicData.imageInfos); output.write("containsPagedLOD", containsPagedLOD); + output.write("allocatedMemoryLimit", allocatedMemoryLimit); } } diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index b2f150404d..aae5f04c88 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include using namespace vsg; @@ -203,7 +204,7 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR { if (availableSpace < minimumDeviceMemorySize) { - info("MemoryBufferPools::reserveMemory(", totalSize, ") reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); + debug("MemoryBufferPools::reserveMemory(", totalSize, ") reducing minimumDeviceMemorySize = ", minimumDeviceMemorySize, " to ", availableSpace); minimumDeviceMemorySize = availableSpace; } @@ -226,6 +227,10 @@ MemoryBufferPools::DeviceMemoryOffset MemoryBufferPools::reserveMemory(VkMemoryR } } } + else if (throwOutOfDeviceMemoryException) + { + throw vsg::Exception{"MemoryBufferPools::reserve() out of memory", VK_ERROR_OUT_OF_DEVICE_MEMORY}; + } } if (!reservedSlot.first) From 38e6ac42513f5fe2d9344b26d87b4bb5f76eae04 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 26 Jan 2026 14:54:34 +0000 Subject: [PATCH 15/15] Removed no longer required include --- src/vsg/vk/MemoryBufferPools.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vsg/vk/MemoryBufferPools.cpp b/src/vsg/vk/MemoryBufferPools.cpp index aae5f04c88..10fe7150bd 100644 --- a/src/vsg/vk/MemoryBufferPools.cpp +++ b/src/vsg/vk/MemoryBufferPools.cpp @@ -15,7 +15,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include -#include using namespace vsg;