Vulkan Cookbook 第四章 6 分配内存对象和将其绑定到图像

分配内存对象和将其绑定到图像

译者注:示例代码点击此处

与缓冲区类似,图像不是使用绑定的内存存储创建的。我们需要隐式创建一个内存对象并将其绑定到图像。也可以使用现有内存来实现此目的。

译者注:图像不是使用绑定的内存存储创建的原文are not created with a bound memory storage。这句话的意思是说,创建了图像对象但是并没有绑定内存,我们需要自己去为它绑定好内存。

怎么做...

1.获取创建逻辑设备的物理设备句柄。将其存储在名为physical_device的VkPhysicalDevice类型变量中。
2.创建名为physical_device_memory_properties的VkPhysicalDeviceMemoryProperties类型变量。
3.调用vkGetPhysicalDeviceMemoryProperties( physical_device, &physical_device_memory_properties ),为其提供物理设备句柄和指向physical_device_memory_properties变量的指针。此调用将获取物理设备内存参数(堆的数量,大小和类型)。
4.获取从物理设备创建的逻辑设备的句柄,将句柄储存在名为logical_device的VkDevice类型变量中。
5.获取由名为image的VkImage类型变量表示的已创建的图像句柄。
6.创建名为memory_requirements的VkMemoryRequirements类型变量。
7.获取需要用于图像的内存参数。通过调用vkGetImageMemoryRequirements( logical_device, image, &memory_requirements )并在第一个参数中提供逻辑设备句柄,在第二个参数中提供创建的图像句柄,以及在第三个参数中提供指向memory_requirements变量的指针来完成。
8.创建一个名为memory_object的VkDeviceMemory类型变量,它将表示为图像创建的内存对象,并为其分配VK_NULL_HANDLE值。
9.创建名为memory_properties的VkMemoryPropertyFlagBits类型变量。在变量中储存其他(选定的)内存属性,如果不需要其他属性,则为0值。
10.迭代可用的物理设备的内存类型。次数为physical_device_memory_properties变量的memoryTypeCount成员变量,通过使用名为type的uint32_t类型变量类型的变量来执行此操作。对于每次迭代:
    1.确保设置了memory_requirements变量的memoryTypeBits成员的位。
    2.确保memory_properties变量在physical_device_memory_properties变量中的索引类型具有与内存类型memoryTypes的propertyFlags成员相同的位。
    3.如果第1点和第2点不成立,则继续迭代循环。
    4.创建名为image_memory_allocate_info的VkMemoryAllocateInfo类型变量,并为其成员分配以下值:
        ·sType为VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
        ·pNext为nullptr
        ·allocationSize为memory_requirements.size
        memoryTypeIndex为type
    5.调用vkAllocateMemory( logical_device, &image_memory_allocate_info, nullptr, &memory_object),为其提供逻辑设备的句柄,指向image_memory_allocate_info变量的指针,nullptr值以及指向memory_object变量的指针。
    6.通过检查调用返回的值是否等于VK_SUCCESS来确保调用成功,并停止迭代循环。
11.通过检查memory_object变量是否不等于VK_NULL_HANDLE,确保循环内的内存对象分配成功。
12.通过调用vkAllocateMemory( logical_device, &image_memory_allocate_info, nullptr, &memory_object )将内存对象绑定到图像,为其提供逻辑设备句柄,指向image_memory_allocate_info变量的指针,nullptr值以及指向memory_object变量的指针。
13.确保调用成功,返回值等于VK_SUCCESS。

这个怎么运作...

与为缓冲区创建内存对象类似,我们首先检查给定物理设备上可用的内存类型以及他们的属性,当然,我们可以忽略这些步骤,并在应用程序初始化阶段一次性收集这些信息:

VkPhysicalDeviceMemoryProperties physical_device_memory_properties; 
vkGetPhysicalDeviceMemoryProperties( physical_device, &physical_device_memory_properties );

接下来,我们获取给定图像的特定内存要求。这些可以(也可能会)对每个图像都不同,因为它们取决于格式,大小,mipmap和图层的数量以及图像的其他参数:

VkMemoryRequirements memory_requirements;
vkGetImageMemoryRequirements( logical_device, image, &memory_requirements );

接下来是找具有适当参数并与图像内存要求兼容的内存类型:

memory_object = VK_NULL_HANDLE;
for( uint32_t type = 0; type < physical_device_memory_properties.memoryTypeCount; ++type ) {
  if( (memory_requirements.memoryTypeBits & (1 << type)) && 
      ((physical_device_memory_properties.memoryTypes[type].propertyFlags & memory_properties) == memory_properties) ) {
      
    VkMemoryAllocateInfo image_memory_allocate_info = {
      VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 
      nullptr,
      memory_requirements.size,
      type
    };
    
    VkResult result = vkAllocateMemory( logical_device, &image_memory_allocate_info, nullptr, &memory_object );
    if( VK_SUCCESS == result ) {
      break; 
    }
  } 
}

在这里,我们迭代所有可用的内存类型。如果设置了图像内存属性的memoryTypeBits成员的给定位,则这意味着具有相同编号的内存类型与图像兼容,我们可以将其用于内存对象。还可以检查内存类型的其他属性,找到适合我们需求的属性。例如,如果希望使用可以映射到CPU(主机可见内存host-visible)的内存。

下一步,我们检查循环内的内存对象分配是否成功,如果是,将创建的内存对象与我们的图像绑定:

if( VK_NULL_HANDLE == memory_object ) {
  std::cout << "Could not allocate memory for an image." << std::endl; 
  return false;
}

VkResult result = vkBindImageMemory( logical_device, image, memory_object, 0 ); 
if( VK_SUCCESS != result ) {
  std::cout << "Could not bind memory object to an image." << std::endl;
  return false; 
}

return true;

从现在开始,我们可以将图像用于创建过程中定义的所有用途。

还有更多...

与将内存对象绑定到缓冲区类似,我们应该分配更大的内存对象并将他们的一部分绑定到多个图像。这样驱动程序会跟踪更少数量的内存对象。这可以改善我们的应用程序性能。它还可以准许我们节省一些内存,因为每次分配可能需要比分配期间请求的内存分配更多内存(换句话说,其大小可能总是向上舍入到内存页大小的倍数)。分配更大的内存对象并将他们的一部分重用与多个图像可以省去浪费的区域。

猜你喜欢

转载自blog.csdn.net/qq_19473837/article/details/84908424