From c8e5dd325a4c2dac3652b4c72298dfbbb8b42a10 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 23 Jan 2019 10:27:01 +0100 Subject: [PATCH 1/2] VK device allocator: Support separate memory type per slab. --- Common/Vulkan/VulkanMemory.cpp | 16 +++++++--------- Common/Vulkan/VulkanMemory.h | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index a6457af0b2..3d2c7dcf3c 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -195,12 +195,6 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic if (!pass) { return ALLOCATE_FAILED; } - if (memoryTypeIndex_ == UNDEFINED_MEMORY_TYPE) { - memoryTypeIndex_ = memoryTypeIndex; - } else if (memoryTypeIndex_ != memoryTypeIndex) { - assert(memoryTypeIndex_ == memoryTypeIndex); - return ALLOCATE_FAILED; - } size_t size = reqs.size; @@ -213,6 +207,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic // This helps us "creep forward", and also spend less time allocating. const size_t actualSlab = (lastSlab_ + i) % numSlabs; Slab &slab = slabs_[actualSlab]; + if (slab.memoryTypeIndex != memoryTypeIndex) + continue; size_t start = slab.nextFree; while (start < slab.usage.size()) { @@ -227,7 +223,7 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic } // Okay, we couldn't fit it into any existing slabs. We need a new one. - if (!AllocateSlab(size)) { + if (!AllocateSlab(size, memoryTypeIndex)) { return ALLOCATE_FAILED; } @@ -401,16 +397,17 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) { delete userdata; } -bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) { +bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex) { assert(!destroyed_); if (!slabs_.empty() && minSlabSize_ < maxSlabSize_) { // We're allocating an additional slab, so rachet up its size. + // TODO: Maybe should not do this when we are allocating a new slab due to memoryTypeIndex not matching? minSlabSize_ <<= 1; } VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; alloc.allocationSize = minSlabSize_; - alloc.memoryTypeIndex = memoryTypeIndex_; + alloc.memoryTypeIndex = memoryTypeIndex; while (alloc.allocationSize < minBytes) { alloc.allocationSize <<= 1; @@ -427,6 +424,7 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) { slabs_.resize(slabs_.size() + 1); Slab &slab = slabs_[slabs_.size() - 1]; + slab.memoryTypeIndex = memoryTypeIndex; slab.deviceMemory = deviceMemory; slab.usage.resize((size_t)(alloc.allocationSize >> SLAB_GRAIN_SHIFT)); diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index 05d892cd1b..ef14de80ed 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -174,6 +174,7 @@ private: struct Slab { VkDeviceMemory deviceMemory; + uint32_t memoryTypeIndex = UNDEFINED_MEMORY_TYPE; std::vector usage; std::unordered_map allocSizes; std::unordered_map tags; @@ -200,7 +201,7 @@ private: freeInfo->allocator->ExecuteFree(freeInfo); // this deletes freeInfo } - bool AllocateSlab(VkDeviceSize minBytes); + bool AllocateSlab(VkDeviceSize minBytes, int memoryTypeIndex); bool AllocateFromSlab(Slab &slab, size_t &start, size_t blocks, const std::string &tag); void Decimate(); void DoTouch(VkDeviceMemory deviceMemory, size_t offset); @@ -212,6 +213,5 @@ private: size_t lastSlab_ = 0; size_t minSlabSize_; const size_t maxSlabSize_; - uint32_t memoryTypeIndex_ = UNDEFINED_MEMORY_TYPE; bool destroyed_ = false; }; From 46585a5da9a276499e78afdcf5d6ced311eef86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Jan 2019 18:34:25 +0100 Subject: [PATCH 2/2] Additional logging --- Common/Vulkan/VulkanContext.cpp | 8 ++++++++ Common/Vulkan/VulkanImage.cpp | 6 ++++++ Common/Vulkan/VulkanMemory.cpp | 2 +- android/jni/AndroidVulkanContext.cpp | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index aeb29f20ea..d222576e5e 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -507,6 +507,14 @@ void VulkanContext::ChooseDevice(int physical_device) { // This is as good a place as any to do this vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties); + ILOG("Memory Types (%d):", memory_properties.memoryTypeCount); + for (int i = 0; i < memory_properties.memoryTypeCount; i++) { + ILOG(" %d: Heap %d; Flags: %s%s%s%s ", i, memory_properties.memoryTypes[i].heapIndex, + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "DEVICE_LOCAL_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "HOST_VISIBLE_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "HOST_CACHED_BIT" : "", + (memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT_BIT" : ""); + } // Optional features vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &featuresAvailable_); diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 4528e4b375..1db379e2ab 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -67,6 +67,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image_); if (res != VK_SUCCESS) { _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); + ELOG("vkCreateImage failed: %s", VulkanResultToString(res)); return false; } @@ -76,6 +77,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, if (allocator_) { offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { + vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); + ELOG("Image memory allocation failed (mem_reqs.size = %d)", (int)mem_reqs.size); return false; } } else { @@ -89,6 +92,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem_); if (res != VK_SUCCESS) { + ELOG("vkAllocateMemory failed: %s", VulkanResultToString(res)); _assert_msg_(G3D, res != VK_ERROR_TOO_MANY_OBJECTS, "Too many Vulkan memory objects!"); _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); vkDestroyImage(vulkan_->GetDevice(), image_, nullptr); @@ -101,6 +105,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkBindImageMemory(vulkan_->GetDevice(), image_, mem_, offset_); if (res != VK_SUCCESS) { + ELOG("vkBindImageMemory failed: %s", VulkanResultToString(res)); // This leaks the image and memory. Should not really happen though... _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; @@ -144,6 +149,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view_); if (res != VK_SUCCESS) { + ELOG("vkCreateImageView failed: %s", VulkanResultToString(res)); // This leaks the image. _assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS); return false; diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 3d2c7dcf3c..2b13be2e01 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -191,8 +191,8 @@ size_t VulkanDeviceAllocator::Allocate(const VkMemoryRequirements &reqs, VkDevic assert(!destroyed_); uint32_t memoryTypeIndex; bool pass = vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex); - assert(pass); if (!pass) { + ELOG("Failed to pick an appropriate memory type (req: %08x)", reqs.memoryTypeBits); return ALLOCATE_FAILED; } diff --git a/android/jni/AndroidVulkanContext.cpp b/android/jni/AndroidVulkanContext.cpp index 0e597e0a7e..776d553066 100644 --- a/android/jni/AndroidVulkanContext.cpp +++ b/android/jni/AndroidVulkanContext.cpp @@ -130,6 +130,7 @@ bool AndroidVulkanContext::InitAPI() { g_Vulkan = nullptr; return false; } + ILOG("Vulkan device created!"); return true; }