910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.


#include "gpu/vulkan/vma_wrapper.h"

#include <vk_mem_alloc.h>

#include <algorithm>
#include <array>

#include "base/check_op.h"
#include "build/build_config.h"
#include "gpu/vulkan/vulkan_function_pointers.h"

namespace gpu {
namespace vma {

VkResult CreateAllocator(VkPhysicalDevice physical_device,
                         VkDevice device,
                         VkInstance instance,
                         const gfx::ExtensionSet& enabled_extensions,
                         const VkDeviceSize preferred_large_heap_block_size,
                         const VkDeviceSize* heap_size_limit,
                         const bool is_thread_safe,
                         VmaAllocator* pAllocator) {
  auto* function_pointers = gpu::GetVulkanFunctionPointers();
  VmaVulkanFunctions functions = {};
  functions.vkGetPhysicalDeviceProperties =
      function_pointers->vkGetPhysicalDeviceProperties.get();
  functions.vkGetPhysicalDeviceMemoryProperties =
      function_pointers->vkGetPhysicalDeviceMemoryProperties.get();
  functions.vkAllocateMemory = function_pointers->vkAllocateMemory.get();
  functions.vkFreeMemory = function_pointers->vkFreeMemory.get();
  functions.vkMapMemory = function_pointers->vkMapMemory.get();
  functions.vkUnmapMemory = function_pointers->vkUnmapMemory.get();
  functions.vkFlushMappedMemoryRanges =
      function_pointers->vkFlushMappedMemoryRanges.get();
  functions.vkInvalidateMappedMemoryRanges =
      function_pointers->vkInvalidateMappedMemoryRanges.get();
  functions.vkBindBufferMemory = function_pointers->vkBindBufferMemory.get();
  functions.vkBindImageMemory = function_pointers->vkBindImageMemory.get();
  functions.vkGetBufferMemoryRequirements =
      function_pointers->vkGetBufferMemoryRequirements.get();
  functions.vkGetImageMemoryRequirements =
      function_pointers->vkGetImageMemoryRequirements.get();
  functions.vkCreateBuffer = function_pointers->vkCreateBuffer.get();
  functions.vkDestroyBuffer = function_pointers->vkDestroyBuffer.get();
  functions.vkCreateImage = function_pointers->vkCreateImage.get();
  functions.vkDestroyImage = function_pointers->vkDestroyImage.get();
  functions.vkCmdCopyBuffer = function_pointers->vkCmdCopyBuffer.get();
  functions.vkGetBufferMemoryRequirements2KHR =
      function_pointers->vkGetBufferMemoryRequirements2.get();
  functions.vkGetImageMemoryRequirements2KHR =
      function_pointers->vkGetImageMemoryRequirements2.get();
  functions.vkBindBufferMemory2KHR =
      function_pointers->vkBindBufferMemory2.get();
  functions.vkBindImageMemory2KHR = function_pointers->vkBindImageMemory2.get();
  functions.vkGetPhysicalDeviceMemoryProperties2KHR =
      function_pointers->vkGetPhysicalDeviceMemoryProperties2.get();

  static_assert(kVulkanRequiredApiVersion >= VK_API_VERSION_1_1, "");
  VmaAllocatorCreateInfo allocator_info = {
      .physicalDevice = physical_device,
      .device = device,
      .preferredLargeHeapBlockSize = preferred_large_heap_block_size,
      .pHeapSizeLimit = heap_size_limit,
      .pVulkanFunctions = &functions,
      .instance = instance,
      .vulkanApiVersion = kVulkanRequiredApiVersion,
  };

  // Note that this extension is only requested on android as of now as a part
  // of optional extensions in VulkanImplementation.
  bool vk_ext_memory_budget_supported = gfx::HasExtension(
      enabled_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);

  // Enable VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT flag if extension is
  // available.
  if (vk_ext_memory_budget_supported) {
    allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
  }

  // If DrDc is not enabled, use below flag which improves performance since
  // internal mutex will not be used.
  // TODO(vikassoni) : Analyze the perf impact of not using this flag and hence
  // enabling internal mutex which will be use for every vma access with DrDc.
  if (!is_thread_safe) {
    allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
  }
  return vmaCreateAllocator(&allocator_info, pAllocator);
}

void DestroyAllocator(VmaAllocator allocator) {
  vmaDestroyAllocator(allocator);
}

VkResult AllocateMemoryForImage(VmaAllocator allocator,
                                VkImage image,
                                const VmaAllocationCreateInfo* create_info,
                                VmaAllocation* allocation,
                                VmaAllocationInfo* allocation_info) {
  return vmaAllocateMemoryForImage(allocator, image, create_info, allocation,
                                   allocation_info);
}

VkResult AllocateMemoryForBuffer(VmaAllocator allocator,
                                 VkBuffer buffer,
                                 const VmaAllocationCreateInfo* create_info,
                                 VmaAllocation* allocation,
                                 VmaAllocationInfo* allocation_info) {
  return vmaAllocateMemoryForBuffer(allocator, buffer, create_info, allocation,
                                    allocation_info);
}

VkResult CreateBuffer(VmaAllocator allocator,
                      const VkBufferCreateInfo* buffer_create_info,
                      VkMemoryPropertyFlags required_flags,
                      VkMemoryPropertyFlags preferred_flags,
                      VkBuffer* buffer,
                      VmaAllocation* allocation) {
  VmaAllocationCreateInfo allocation_create_info = {
      .requiredFlags = required_flags,
      .preferredFlags = preferred_flags,
  };

  return vmaCreateBuffer(allocator, buffer_create_info, &allocation_create_info,
                         buffer, allocation, nullptr);
}

void DestroyBuffer(VmaAllocator allocator,
                   VkBuffer buffer,
                   VmaAllocation allocation) {
  vmaDestroyBuffer(allocator, buffer, allocation);
}

VkResult MapMemory(VmaAllocator allocator,
                   VmaAllocation allocation,
                   void** data) {
  return vmaMapMemory(allocator, allocation, data);
}

void UnmapMemory(VmaAllocator allocator, VmaAllocation allocation) {
  return vmaUnmapMemory(allocator, allocation);
}

void FreeMemory(VmaAllocator allocator, VmaAllocation allocation) {
  vmaFreeMemory(allocator, allocation);
}

VkResult FlushAllocation(VmaAllocator allocator,
                         VmaAllocation allocation,
                         VkDeviceSize offset,
                         VkDeviceSize size) {
  return vmaFlushAllocation(allocator, allocation, offset, size);
}

VkResult InvalidateAllocation(VmaAllocator allocator,
                              VmaAllocation allocation,
                              VkDeviceSize offset,
                              VkDeviceSize size) {
  return vmaInvalidateAllocation(allocator, allocation, offset, size);
}

void GetAllocationInfo(VmaAllocator allocator,
                       VmaAllocation allocation,
                       VmaAllocationInfo* allocation_info) {
  vmaGetAllocationInfo(allocator, allocation, allocation_info);
}

void GetMemoryTypeProperties(VmaAllocator allocator,
                             uint32_t memory_type_index,
                             VkMemoryPropertyFlags* flags) {
  vmaGetMemoryTypeProperties(allocator, memory_type_index, flags);
}

void GetPhysicalDeviceProperties(
    VmaAllocator allocator,
    const VkPhysicalDeviceProperties** physical_device_properties) {
  vmaGetPhysicalDeviceProperties(allocator, physical_device_properties);
}

void GetBudget(VmaAllocator allocator, VmaBudget* budget) {
  vmaGetHeapBudgets(allocator, budget);
}

std::pair<uint64_t, uint64_t> GetTotalAllocatedAndUsedMemory(
    VmaAllocator allocator) {
  // See VulkanAMDMemoryAllocator::totalAllocatedAndUsedMemory() in skia for
  // reference.
  std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> budget;
  GetBudget(allocator, budget.data());
  const VkPhysicalDeviceMemoryProperties* pPhysicalDeviceMemoryProperties;
  vmaGetMemoryProperties(allocator, &pPhysicalDeviceMemoryProperties);
  uint64_t total_allocated_memory = 0, total_used_memory = 0;
  for (uint32_t i = 0; i < pPhysicalDeviceMemoryProperties->memoryHeapCount;
       ++i) {
    total_allocated_memory += budget[i].statistics.blockBytes;
    total_used_memory += budget[i].statistics.allocationBytes;
  }
  DCHECK_LE(total_used_memory, total_allocated_memory);

  return {total_allocated_memory, total_used_memory};
}

}  // namespace vma
}  // namespace gpu