diff --git a/src/gpgmm/vk/FunctionsVk.cpp b/src/gpgmm/vk/FunctionsVk.cpp index fa08bb341..d2a040e54 100644 --- a/src/gpgmm/vk/FunctionsVk.cpp +++ b/src/gpgmm/vk/FunctionsVk.cpp @@ -45,11 +45,12 @@ namespace gpgmm::vk { GPGMM_DYNAMIC_GET_DEVICE_FUNC(AllocateMemory); GPGMM_DYNAMIC_GET_DEVICE_FUNC(FreeMemory); GPGMM_DYNAMIC_GET_DEVICE_FUNC(BindBufferMemory); + GPGMM_DYNAMIC_GET_DEVICE_FUNC(BindImageMemory); GPGMM_DYNAMIC_GET_DEVICE_FUNC(GetBufferMemoryRequirements); GPGMM_DYNAMIC_GET_DEVICE_FUNC(GetImageMemoryRequirements); GPGMM_DYNAMIC_GET_DEVICE_FUNC(CreateBuffer); - GPGMM_DYNAMIC_GET_DEVICE_FUNC(DestroyBuffer); GPGMM_DYNAMIC_GET_DEVICE_FUNC(CreateImage); + GPGMM_DYNAMIC_GET_DEVICE_FUNC(DestroyBuffer); GPGMM_DYNAMIC_GET_DEVICE_FUNC(DestroyImage); // TODO } @@ -60,11 +61,12 @@ namespace gpgmm::vk { GPGMM_STATIC_GET_FUNC(AllocateMemory); GPGMM_STATIC_GET_FUNC(FreeMemory); GPGMM_STATIC_GET_FUNC(BindBufferMemory); + GPGMM_STATIC_GET_FUNC(BindImageMemory); GPGMM_STATIC_GET_FUNC(GetBufferMemoryRequirements); GPGMM_STATIC_GET_FUNC(GetImageMemoryRequirements); GPGMM_STATIC_GET_FUNC(CreateBuffer); - GPGMM_STATIC_GET_FUNC(DestroyBuffer); GPGMM_STATIC_GET_FUNC(CreateImage); + GPGMM_STATIC_GET_FUNC(DestroyBuffer); GPGMM_STATIC_GET_FUNC(DestroyImage); // TODO } @@ -75,11 +77,12 @@ namespace gpgmm::vk { AllocateMemory = vkFunctions->AllocateMemory; FreeMemory = vkFunctions->FreeMemory; BindBufferMemory = vkFunctions->BindBufferMemory; + BindImageMemory = vkFunctions->BindImageMemory; GetBufferMemoryRequirements = vkFunctions->GetBufferMemoryRequirements; GetImageMemoryRequirements = vkFunctions->GetImageMemoryRequirements; CreateBuffer = vkFunctions->CreateBuffer; - DestroyBuffer = vkFunctions->DestroyBuffer; CreateImage = vkFunctions->CreateImage; + DestroyBuffer = vkFunctions->DestroyBuffer; DestroyImage = vkFunctions->DestroyImage; } @@ -89,11 +92,12 @@ namespace gpgmm::vk { ASSERT(vkFunctions.AllocateMemory != nullptr); ASSERT(vkFunctions.FreeMemory != nullptr); ASSERT(vkFunctions.BindBufferMemory != nullptr); + ASSERT(vkFunctions.BindImageMemory != nullptr); ASSERT(vkFunctions.GetBufferMemoryRequirements != nullptr); ASSERT(vkFunctions.GetImageMemoryRequirements != nullptr); ASSERT(vkFunctions.CreateBuffer != nullptr); - ASSERT(vkFunctions.DestroyBuffer != nullptr); ASSERT(vkFunctions.CreateImage != nullptr); + ASSERT(vkFunctions.DestroyBuffer != nullptr); ASSERT(vkFunctions.DestroyImage != nullptr); } diff --git a/src/gpgmm/vk/FunctionsVk.h b/src/gpgmm/vk/FunctionsVk.h index c95dc2608..a5dd5b4ac 100644 --- a/src/gpgmm/vk/FunctionsVk.h +++ b/src/gpgmm/vk/FunctionsVk.h @@ -37,14 +37,15 @@ namespace gpgmm::vk { PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties = nullptr; PFN_vkAllocateMemory AllocateMemory = nullptr; PFN_vkBindBufferMemory BindBufferMemory = nullptr; + PFN_vkBindImageMemory BindImageMemory = nullptr; PFN_vkFreeMemory FreeMemory = nullptr; PFN_vkMapMemory MapMemory = nullptr; PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements = nullptr; PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements = nullptr; PFN_vkCreateBuffer CreateBuffer = nullptr; - PFN_vkDestroyBuffer DestroyBuffer = nullptr; PFN_vkCreateImage CreateImage = nullptr; PFN_vkDestroyImage DestroyImage = nullptr; + PFN_vkDestroyBuffer DestroyBuffer = nullptr; }; // ASSERTs if any Vulkan function is left unset. diff --git a/src/gpgmm/vk/ResourceAllocatorVk.cpp b/src/gpgmm/vk/ResourceAllocatorVk.cpp index 5a49311ea..f65e105ce 100644 --- a/src/gpgmm/vk/ResourceAllocatorVk.cpp +++ b/src/gpgmm/vk/ResourceAllocatorVk.cpp @@ -109,6 +109,74 @@ namespace gpgmm::vk { allocator->DeallocateMemory(allocation); } + VkResult gpCreateImage(GpResourceAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + VkImage* imageOut, + const GpResourceAllocationCreateInfo* pAllocationCreateInfo, + GpResourceAllocation* allocationOut) { + *allocationOut = VK_NULL_HANDLE; + *imageOut = VK_NULL_HANDLE; + + if (allocator == VK_NULL_HANDLE) { + return VK_INCOMPLETE; + } + + // Create the image. + VkImage image = VK_NULL_HANDLE; + ReturnIfFailed( + allocator->GetFunctions().CreateImage(allocator->GetDevice(), pImageCreateInfo, + /*allocationCallbacks*/ nullptr, &image)); + + VkMemoryRequirements requirements = {}; + allocator->GetImageMemoryRequirements(image, &requirements); + if (requirements.size == 0) { + return VK_INCOMPLETE; + } + + // Create memory for the image. + GpResourceAllocation allocation = VK_NULL_HANDLE; + VkResult result = + allocator->TryAllocateMemory(requirements, *pAllocationCreateInfo, &allocation); + if (result != VK_SUCCESS) { + allocator->GetFunctions().DestroyImage(allocator->GetDevice(), image, + /*allocationCallbacks*/ nullptr); + return result; + } + + // Associate memory with the buffer. + result = allocator->GetFunctions().BindImageMemory( + allocator->GetDevice(), image, ToBackend(allocation->GetMemory())->GetDeviceMemory(), + allocation->GetOffset()); + if (result != VK_SUCCESS) { + allocator->GetFunctions().DestroyImage(allocator->GetDevice(), image, + /*allocationCallbacks*/ nullptr); + allocator->DeallocateMemory(allocation); + return result; + } + + *allocationOut = allocation; + *imageOut = image; + + return VK_SUCCESS; + } + + void gpDestroyImage(GpResourceAllocator allocator, + VkImage image, + GpResourceAllocation allocation) { + if (allocator == VK_NULL_HANDLE || image == VK_NULL_HANDLE) { + return; + } + + allocator->GetFunctions().DestroyImage(allocator->GetDevice(), image, + /*allocationCallbacks*/ nullptr); + + if (allocation == VK_NULL_HANDLE) { + return; + } + + allocator->DeallocateMemory(allocation); + } + // GpResourceAllocation_T GpResourceAllocation_T::GpResourceAllocation_T(const MemoryAllocation& allocation) @@ -146,8 +214,17 @@ namespace gpgmm::vk { caps.reset(ptr); } + GpAllocatorCreateInfo newInfo = info; + newInfo.MemoryGrowthFactor = (newInfo.MemoryGrowthFactor >= 1.0) + ? newInfo.MemoryGrowthFactor + : kDefaultMemoryGrowthFactor; + + newInfo.MemoryFragmentationLimit = (newInfo.MemoryFragmentationLimit > 0) + ? newInfo.MemoryFragmentationLimit + : kDefaultFragmentationLimit; + if (allocatorOut != VK_NULL_HANDLE) { - *allocatorOut = new GpResourceAllocator_T(info, vulkanFunctions, std::move(caps)); + *allocatorOut = new GpResourceAllocator_T(newInfo, vulkanFunctions, std::move(caps)); } return VK_SUCCESS; @@ -223,6 +300,11 @@ namespace gpgmm::vk { mVulkanFunctions.GetBufferMemoryRequirements(mDevice, buffer, requirementsOut); } + void GpResourceAllocator_T::GetImageMemoryRequirements(VkImage image, + VkMemoryRequirements* requirementsOut) { + mVulkanFunctions.GetImageMemoryRequirements(mDevice, image, requirementsOut); + } + VkResult GpResourceAllocator_T::TryAllocateMemory(const VkMemoryRequirements& requirements, const GpResourceAllocationCreateInfo& info, GpResourceAllocation* allocationOut) { diff --git a/src/gpgmm/vk/ResourceAllocatorVk.h b/src/gpgmm/vk/ResourceAllocatorVk.h index df594bd4b..ecd78c105 100644 --- a/src/gpgmm/vk/ResourceAllocatorVk.h +++ b/src/gpgmm/vk/ResourceAllocatorVk.h @@ -298,6 +298,32 @@ namespace gpgmm::vk { VkBuffer buffer, GpResourceAllocation allocation); + /** \brief Create a image allocation. + + @param allocator A GpResourceAllocator used to create the image and allocation. + @param pImageCreateInfo A pointer to a VkImageCreateInfo that describes the image to create. + @param pImage A pointer to a VkImage that will be created using the allocation. + @param pAllocationCreateInfo A pointer to a GpResourceAllocationCreateInfo that describes the + allocation. + @param[out] allocationOut A pointer to GpResourceAllocation that represents the image + allocation. + */ + GPGMM_EXPORT VkResult gpCreateImage(GpResourceAllocator allocator, + const VkImageCreateInfo* pImageCreateInfo, + VkImage* pImage, + const GpResourceAllocationCreateInfo* pAllocationCreateInfo, + GpResourceAllocation* allocationOut); + + /** \brief Destroy image allocation. + + @param allocator A GpResourceAllocator used to create the image and allocation. + @param image A VkImage that was also created by the allocator. + @param allocation A GpResourceAllocation that was created by the allocator. + */ + GPGMM_EXPORT void gpDestroyImage(GpResourceAllocator allocator, + VkImage image, + GpResourceAllocation allocation); + struct GpResourceAllocation_T final : public MemoryAllocation { GpResourceAllocation_T(const MemoryAllocation& allocation); }; @@ -315,6 +341,7 @@ namespace gpgmm::vk { void DeallocateMemory(GpResourceAllocation allocation); void GetBufferMemoryRequirements(VkBuffer buffer, VkMemoryRequirements* requirementsOut); + void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements* requirementsOut); VkDevice GetDevice() const; VulkanFunctions GetFunctions() const; diff --git a/src/tests/end2end/VKResourceAllocatorTests.cpp b/src/tests/end2end/VKResourceAllocatorTests.cpp index 7fdf58a15..153aadd78 100644 --- a/src/tests/end2end/VKResourceAllocatorTests.cpp +++ b/src/tests/end2end/VKResourceAllocatorTests.cpp @@ -58,6 +58,35 @@ TEST_F(VKResourceAllocatorTests, CreateBuffer) { gpDestroyResourceAllocator(resourceAllocator); } +TEST_F(VKResourceAllocatorTests, CreateImage) { + GpResourceAllocator resourceAllocator; + ASSERT_SUCCESS(gpCreateResourceAllocator(CreateBasicAllocatorInfo(), &resourceAllocator)); + + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.extent.width = 1; + imageInfo.extent.height = 1; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.flags = 0; + + GpResourceAllocationCreateInfo allocationInfo = {}; + + VkImage image; + GpResourceAllocation allocation; + ASSERT_SUCCESS( + gpCreateImage(resourceAllocator, &imageInfo, &image, &allocationInfo, &allocation)); + + gpDestroyImage(resourceAllocator, image, allocation); + gpDestroyResourceAllocator(resourceAllocator); +} + TEST_F(VKResourceAllocatorTests, CreateBufferManyDeallocateAtEnd) { GpResourceAllocator resourceAllocator; ASSERT_SUCCESS(gpCreateResourceAllocator(CreateBasicAllocatorInfo(), &resourceAllocator));